iOS学习:iOS代码规范_ios replaceobjectsinrange-程序员宅基地

技术标签: iOS代码规范  ios  

本文已收录到GitHub, 喜欢的朋友可以Star一下: iOSRegulations


作者感言

这篇文章, 部分是收集了网上的iOS开发爱好者的代码规范, 以及我自己的理解, 不一定完全满足所有人, 希望多多见谅, 也同样感谢支持我完成这篇文章的朋友.

刚开始写这篇文章的时候, 我无从下手, 直到我朋友给了我一份JAVA的开发文档规范, 我才慢慢有了清晰的思路, 中间迭代了许多版本, 一次次的修改文章的排版, 关键字的高亮, 以及代码的高亮.

一点点的编写, 一次次的修改, 让我对代码规范有了更深刻的理解, 曾经有人说过, 印度人写代码, 100个人所写的, 看起来像一个人所写的, 不是说印度阿三开挂了, 是他们遵循了一个规范, 无规矩不成方圆, 也就是这个道理.

最后:
如果你有更好的建议或者对这篇文章有不满的地方, 请联系我, 我会参考你们的意见再进行修改, 联系我时, 请备注iOS代码规范文档, 祝大家学习愉快~谢谢~

Cain(罗家辉)

[email protected]: 联系方式

350116542: 腾讯QQ


阅读前言

@(Reading Preface)


  • 在阅读代码规范之前,必须先去下载两个插件<XAlign, VVDocumenter>。

  • 文档的目的是描述一些关于iOS编程的标准和惯例,并指导编写稳定的iOS代码。
  • 这些都是基于健全的、充分证明过的软件工程基础上的,并使得代码容易理解、维护和增。
  • 更重要的是,遵循这些规则,iOS开发人员的编程效率将会显著的得到提高。
  • 因为不必花费时间来重新编写代码,而是更容易的在开发过程中,对代码进行修改。
  • 最后,遵循这些规则,可以保持代码的连续性和粘性,提升开发组的效率。

iOS代码规范

@(Code)[Standard]


#Import规范

  1. 当一个Controller或者一个Class中需要用到不同的类和Define时, 我们应当把#import划分.
  • 划分原则: 哪个Controller或者Class是本Controller或者Class的次级就放在一起, 公共ControllerClass就与之前的空一行, 紧跟着下面.

比如:

#import "AspManageServicePasswordViewController.h"
#import "AspResetServicePasswordViewController.h"
#import "AspServicePasswordView.h"

#import "NorNavShareView.h"

#import "AppDelegate.h"
#import "BCTabBarView.h"

#import "ModifyPwdViewController.h"
#import "AspLoginVC.h"

#Define规范

  1. 使用#define时, 必须要以数值对齐.

比如:

#define kLabelSize     20
#define kLabelMargins  20

#define kConfirmBottom 63

错误写法:

#define kLabelSize 20
#define kLabelMargins 20

#define kConfirmBottom 63

  1. 使用#define定义预编译宏时, 应当把宏定义成全部大写字母, 且与“_”分隔, 此方法是苹果官方所推荐.

比如:

#define NS_AVAILABLE(_mac, _ios) CF_AVAILABLE(_mac, _ios)
#define NS_AVAILABLE_MAC(_mac) CF_AVAILABLE_MAC(_mac)
#define NS_AVAILABLE_IOS(_ios) CF_AVAILABLE_IOS(_ios)

错误写法:

#define kCancelBottom  25
#define kCancelHeight  44
#define kCancelMargins 25
  1. 在代码中尽量减少在代码中直接使用数字敞亮, 而使用#define来进行声明常量或运算.

比如:

#define kTableViewHeight     300
#define kTableViewCellHeight label.height + view.height

错误写法:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.frame = CGRectMake(0, 64, 320, 660);
}
  1. 尽量代码中得重复计算, 比如在代码中很多地方需要使用到屏幕的宽度, 然后再进行计算, 我们就可以把屏幕的宽度进行抽取封装成#define.

比如:

#define AspScreenWidth   ([[UIScreen mainScreen] bounds].size.width)
#define kTableViewHeight 300
#define NAV_VIEW_HEIGHT  64

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.frame = CGRectMake(0, NAV_VIEW_HEIGHT, AspScreenWidth, kTableViewHeight);
}

错误写法:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tableView.frame = CGRectMake(0, 64, 320, 660);
}

#Paragma Mark 规范

  1. 使用#pragma mark时紧挨着方法名, 且与上一个方法的间距为1空行.

比如:

- (void)mineViewModel {

    // Code Body
}

#pragma mark - TableViewRefresh
- (void)pulldownRefresh:(AspTableView *)tableView {

    [self.mineViewModel requestDataWithSuccess:nil failure:nil];
}

错误写法:

- (void)mineViewModel {

    // Code Body
}

#pragma mark - TableViewRefresh

- (void)pulldownRefresh:(AspTableView *)tableView {

    [self.mineViewModel requestDataWithSuccess:nil failure:nil];
}

- (void)mineViewModel {

    // Code Body
}
#pragma mark - TableViewRefresh
- (void)pulldownRefresh:(AspTableView *)tableView {

    [self.mineViewModel requestDataWithSuccess:nil failure:nil];
}

  1. 当两个方法相近或者都是同一个模块里的方法, 使用#pragma mark加注释来导航代码.

比如:

#pragma mark - Some Mothed
- (void)someMothedOne;
- (void)someMothedTwo;
- (void)someMothedThree;

错误写法:

#pragma mark - 
- (void)someMothedOne;
- (void)someMothedTwo;
- (void)someMothedThree;


- (void)someMothedOne;
- (void)someMothedTwo;
- (void)someMothedThree;

@Interface规范

  1. @Interface里遵循的Delegate, 或者是DataSource方法, 必须以,间隔, 且空一格.

比如:

@interface AspEasyOwnResetPasswordViewController () <UITextFieldDelegate, MBAlertViewDelegate, UITableVIewDelegate, UITextViewDelegate, UIAlertViewDelegate, UITableViewDataSource>

错误写法:

@interface AspEasyOwnResetPasswordViewController()<UITextFieldDelegate,MBAlertViewDelegate>

  1. 当我们在@interface里声明变量时, 我们应该根据内存管理关键字来划分模块, 且以 “*” 分类对齐(基础数据类型除外).

比如:

@interface AspResetServicePasswordViewController () <UITextFieldDelegate, MBAlertViewDelegate>

@property (nonatomic, strong) AspRetrievePasswordView *retrievePassword;
@property (nonatomic, strong) UITextField             *foucsTextField;

@property (nonatomic, copy) NSString *brandName;
@property (nonatomic, copy) NSString *brandType;

@property (nonatomic, assign) NSTimer *timer;

@property (nonatomic, assign) NSInteger zeroCount;
@property (nonatomic, assign) NSInteger verificationCode;

@end

错误写法:

@property (nonatomic, strong) NSDictionary *everyDataDic;
@property (nonatomic, copy) NSString *timeStr;
@property (nonatomic, strong) UILabel *timeLabel;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) SHLineGraphView *lineGraph;

  1. @interface里声明@property需要把nonatomic放在前(使用xib的除外), strong等内存关键字放在后, 且“()”前后各空一格.

比如:

@property (nonatomic, strong) UILabel        *unitLabel;
@property (nonatomic, strong) UIImageView    *bgView;
@property (nonatomic, strong) NSMutableArray *dayDataObjects;

错误写法:

@property ( nonatomic, retain ) UIScrollView*   navScrollView;
@property ( nonatomic, retain ) NSMutableArray* ItemBtns;

@implementation规范

  1. 禁止使用@synthesize关键字, @property已经自动帮我们声明了SetterGetter方法, 如有特殊需求可重写Setter方法, 所以不需要再使用@synthesize.

错误写法:

@implementation FreeExperienceView
@synthesize segment    = _segment;
@synthesize dataInfo   = _dataInfo;
@synthesize delegate   = _delegate;
@synthesize MyEXPView  = _MyEXPView
@synthesize canEXPView = _canEXPView;
@synthesize isRefresh  = _isRefresh;

实例规范

  1. 一个实例变量出现属性赋值时, 如果是以“=”赋值, 必须以“=”对齐, 如果以“[]”赋值, 必须以开头第一个“[”对齐.

比如:

- (void)setTextFieldDelegate:(id<UITextFieldDelegate>)textFieldDelegate {

    self.phoneTextFieldOne.delegate   = textFieldDelegate;
    self.phoneTextFieldTwo.delegate   = textFieldDelegate;
    self.phoneTextFieldThree.delegate = textFieldDelegate;
    self.reviewPassword.delegate      = textFieldDelegate;
    self.confirmPassword.delegate     = textFieldDelegate;
}

错误写法:

- (void)setTextFieldDelegate:(id<UITextFieldDelegate>)textFieldDelegate {

    self.phoneTextFieldOne.delegate = textFieldDelegate;
    self.phoneTextFieldTwo.delegate = textFieldDelegate;
    self.phoneTextFieldThree.delegate = textFieldDelegate;
    self.reviewPassword.delegate = textFieldDelegate;
    self.confirmPassword.delegate = textFieldDelegate;
}

  1. 当出现多个实例变量时, 应该使用代码块的思想, 把它们组成一个模块一个模块(特殊情况除外)比如需要局部声明的AVFoundation.

比如:

- (void)customFunction {

    Person *person = [[Person alloc] init];
    person.name    = @"xiaoming";
    person.age     = 17;

    Car *newCar = [[Car alloc] init];
    newCar.name = @"保时捷";
}

错误写法:

- (void)customFunction {

    Person *person = [[Person alloc] init];
    person.name    = @"xiaoming";
    person.age     = 17;
    Car *newCar = [[Car alloc] init];
    newCar.name = @"保时捷";
}

  1. 禁止在实例对象, 赋值, 调用方法后的“;”与前面代码空格.

比如:

- (void)customFunction:(NSString *)someName {

    self.userName = someName;    
}

错误写法:

- (void)customFunction:(NSString *)someName {

    self.userName = someName ;
}

  1. 在制类型转换时, 函数强转类型与被强转函数名之间不放置空格, 但类型中的Type*必须空格.

比如:

NSString *userName = (NSString *)student;

错误写法:

NSString *userName = (NSString *) student;

NSDictionary规范

  1. NSDictionary里的Key : Value数量大于或者等于2时, 应拆分为多行显示, 并以 ":" 对齐.

比如:

NSDictionary *people = @{@"xiaoming" : 18,
                         @"xiaohong" : 19,
                         @"xiaowang" : 20};         

错误写法:

NSDictionary *people = @{@"xiaoming":18,@"xiaohong":19,@"xiaowang":20};         

NSArray规范

  1. NSArray里的元素数量大于或者等于2时, 应拆分为多行显示, 并以第一个元素对齐.

比如:

NSArray *nameArray = @[@"小明", 
                       @"小红, 
                       @"小王"];         

错误写法:

NSArray *nameArray = @[@"小明",@"小红",@"小王"];         

函数规范

  1. 在声明函数时“-”“(type)”必须空一格, 且后面的参数类型与“*”也必须空一格.

比如:

- (void)customFunction {

    // Code Body
}

错误写法:

-(void)customFunction {

    // Code Body
}
-(void) customFunction {

    // Code Body
}

  1. 方法与方法之间相隔一行的间距, 禁止不空行或多空行.

比如:

- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {
        //Code Body
    }    
    return self;
}

- (void)customFunction {
    //Code Body
}

错误写法:

- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {
        //Code Body
    }    
    return self;
}
- (void)customFunction {
    //Code Body
}
- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {
        //Code Body
    }    
    return self;
}



- (void)customFunction {
    //Code Body
}

  1. 在每个方法定义前需要留白一行, 也就是每个方法之间留空一行, 如果是系统的方法则可以不留空.

比如:

- (void)viewDidLoad {
    [super viewDidLoad];

    // Code Body
}

错误写法:

- (void)viewDidLoad {

    [super viewDidLoad];

    // Code Body
}
- (void)customFunction {
    [self customFunction];

    // Code Body
}

  1. 在函数体内, 如果第一句调用的是系统方法, 可不换行, 如果是自定义的方法(包括if-else和for-in), 必须换行.

比如:

- (void)mineViewModel {

    [self customFunction]
}

错误写法:

- (void)mineViewModel {
    [self customFunction]
}

  1. 在函数体里, 如果只有一句代码, 可与函数名紧挨

比如:

- (NSString *)iconImageName {
    return @"icon_nav5";
}

错误写法:

- (NSString *)iconImageName {   

    return @"icon_nav5";
}

  1. 任意行代码不能超过80个字符, 如果超过80个字符, 可以考虑多行显示, 比如有多个参数时, 可以每个参数放一行.

比如:

- (void)replaceObjectsInRange:(NSRange)range 
         withObjectsFromArray:(NSArray<ObjectType> *)otherArray 
                        range:(NSRange)otherRange; 

错误写法:

- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray<ObjectType> *)otherArray range:(NSRange)otherRange; 
  1. 如果实现的是空函数体, 那么就不需要空格.

比如:

- (void)showView {}

错误写法:

- (void)showView {
}
- (void)showView {

}

If-Else规范

  1. 如果在方法中出现if-else判断, 我们应该使用结构清晰的排版方式, if-else语句与方法名空行, 与return语句可以不用空行.

比如:

- (instancetype)initWithFrame:(CGRect)frame {

    if (self = [super initWithFrame:frame]) {
        // code body
    }
    return self;
}

错误写法:

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // code body
    }
    return self;
}
  1. if-else内部也必须跟着空行, 在else之后的"}"可不空行.

比如:

- (void)viewDidLoad {
    [super viewDidLoad];

    if (age < 0) {

        // Code Body        
    }
}

错误写法:

- (void)viewDidLoad {
    [super viewDidLoad];

    if (age < 0) {
        // Code Body
    }
}
  1. if-else超过四层的时候, 就要考虑重构, 多层的if-else结构很难维护.

比如:

- (void)viewDidLoad {
    [super viewDidLoad];

    if (condition) {

        // Code Body

    } else if (condition){

        // Code Body

    } else if (condition){

        // Code Body

    } else if (condition){

        // Code Body

    } else if (condition){

        // Code Body

    } else if (condition){

        // Code Body

    } else {

        // Code Body
    }
}
  1. 合理使用if-else, 当某个场景只需满足一个条件才能进入if-else时, 应该把if-else抽成一个模块.

比如:

- (void)viewDidLoad {
    [super viewDidLoad];

    if (age < 0) {

        NSLog(@"这是错误的年龄");

        return;
    }

    NSLog(@"现在时%ld岁", (long)age):
}

错误写法:

- (void)viewDidLoad {
    [super viewDidLoad];

    if (age < 0) {

        NSLog(@"这是错误的年龄");

    } else {

        NSLog(@"现在时%ld岁", (long)age):
    }
}

  1. 在使用if-else时必须加"{}"符号, 如果存在else时, 必须加{}

比如:

- (void)customFunction {

    if (condition) {

        // Code Body
    } else {

        // Code Body
    }
}

错误写法:

- (void)customFunction {

    if (condition) // Code Body

    else // Code Body
}
- (void)customFunction {

    if (condition) // Code Body

    // Code Body
}
  1. 在使用if-else中, ()中的条件, 不需要与左右两边的()空格, 且{}与前一个)空格

比如:

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self){

       [self setBackgroundColor:TRAFFICDETAILBACGROUNDCOLOR];

        if (!_ItemBtns) {

           _ItemBtns = [[NSMutableArray alloc] init];
        }

        _mnScrollViewWidth = kWidthToFit(94); 

        self.colorNoSel = UIColorFromRGB(0xdee6ea);
        self.colorSel   = UIColorFromRGB(0xcdd0d2);

        [self addSubview:self.navScrollView];
    }

    return self;
}

错误写法

- (id) initWithFrame:(CGRect)frame {

    self = [super initWithFrame:frame];
    if ( self )
    {
       [self setBackgroundColor:TRAFFICDETAILBACGROUNDCOLOR];

        if ( !_ItemBtns ) {
           _ItemBtns = [[NSMutableArray alloc] init] ;
        }
        _mnScrollViewWidth = kWidthToFit(94); 
        self.colorNoSel = UIColorFromRGB(0xdee6ea) ;
        self.colorSel = UIColorFromRGB(0xcdd0d2) ;

        [self addSubview:self.navScrollView];
    }

    return self;
}

For-In & For 规范

  1. 当函数中需要使用到"for(for-in)", 在"for(for-in)"内, 必须和上文的"if-else"一样空行, 与return语句可不空行.

比如:

- (void)customFunction {

    for (NSInteger i = 0; i < 10; i++) {

        // code body
    }
}

错误写法:

- (void)customFunction {
    for (NSInteger i = 0; i < 10; i++) {
        // code body
    }
}

  1. "for(for-in)"中, 里面的参数必须严格按照上文所示的实例规范来声明, 且是兼容64位的类型.

比如:

- (void)viewDidLoad {
    [super viewDidLoad];

    for (NSInteger i = 0; i < 10; i++) {

        // code body
    }
}

错误写法:

- (void)viewDidLoad {
    [super viewDidLoad];

    for (NSInteger i=0;i<10;i++) {
        // code body
    }
}

  1. 当函数中需要使用到"for(for-in)", 如果该"for(for-in)"是在函数的第一句, 必须和上文的"if-else"一样空行, 与return语句可不空行.

比如:

- (void)customFunction {

    for (NSInteger i = 0; i < 10; i++) {

        // code body
    }
}

错误写法:

- (void)customFunction {
    for (NSInteger i = 0; i < 10; i++) {
        // code body
    }
}

Block规范

  1. 在函数中使用到Block时, 与if-else或者for-in不太一样, Block第一行与代码块必须得空行, 无论方法是否是系统自带的.

比如:

- (void)customFunction {

    [className blockName:^(parameter) {

        // Code Body
    }];
}

错误写法:

- (void)customFunction {

    [className blockName:^(parameter) {
        // Code Body
    }];
}

运算符规范

  1. 一元运算符和参数之间不放置空格, 比如"!"非运算符, "&"安位与, "|"安位或.

比如:

BOOL isOpen  = YES;
BOOL isClose = !isOpen;

错误写法:

BOOL isOpen  = YES;
BOOL isClose = ! isOpen;

BOOL isOpen=YES;
BOOL isClose=!isOpen;

  1. 二元运算符和参数之间要有空格, 如赋值号"="左右各留一个空格.

比如:

self.myString = @“mySring”;

错误写法:

self.myString=@"myString";

  1. 三目运算符和参数之间必须得有空格, 如判断符"?"结果符":"

比如:

NSInteger userAge = @"Man" ? 18 : 19;

错误写法:

NSInteger userAge = @"Man"?18:19;

命名规范

实例命名规范

  1. 使用完整的英文描述来准确描述Variable /Class /Define /Notes, 禁止使用拼音命名, 不建议建议使用缩写.

比如:

NSString *userName = @"小明";

错误写法:

NSString *uName = @"小明";

  1. 使用本行业的专业术语, 如果是消费者的话就要使用消费者对应的名词, 用户的话就使用用户对应的名词, 并且以“=”对齐, 禁止夸域命名.

比如:

NSString *userName = @"小明";
NSInteger userAge  = 18;
CGFloat userHeight = 170.0f;

错误写法:

NSString *uName = @"小明";
NSInteger uAge  = 18;
CGFloat uHeight = 170.5f;

  1. 使用Apple推荐的驼峰命名方式来编写代码, 方法开头第一个字母必须小写(特殊命名除外), 禁止使用随性的命名方式.

比如:

- (CGPoint)convertPoint:(CGPoint)point toView:(nullable UIView *)view;

错误写法:

- (CGPoint)ConverTPoint:(CGPoint)POINT ToView:(nullable UIView *)view;

@Property命名规范

  1. 尽量少用缩写, 使用Apple推荐的短句命名法命名且第一个字母必须小写, 这样子做, 可以省略再注释处理.

比如:

@property (readonly, copy) NSString *decomposedStringWithCanonicalMapping;
@property (readonly, copy) NSString *precomposedStringWithCanonicalMapping;
@property (readonly, copy) NSString *decomposedStringWithCompatibilityMapping;
@property (readonly, copy) NSString *precomposedStringWithCompatibilityMapping;

错误写法:

@property (readonly, copy) NSString *uName;
@property (readonly, assign) NSInteger *uAge;
@property (readonly, assign) CGFloat *uHeight;

@Interface->class命名规范

  1. 尽量使用有意义的英文名字命名, 拒绝使用"i", "j"等无意义的字符命名, 类的命名首字母大写, 其他变量的命名首字符小写.

比如:

@interface People : SuperClassName
@end

错误写法:

@interface people : SuperClassName
@end
@interface ren : SuperClassName
@end

Block命名规范

  1. 尽量使用有意义的命名方法, 禁止使用简称去命名.

比如:

@property (nonatomic, copy) void(^aspWebNavigationRightBtnBlock)(parameter);

错误写法:

@property (nonatomic, copy) void(^aspWNavRBBlock)(parameter);

For-In命名规范

  1. 在使用快速遍历for-in时, 其中的参数需要根据对应的元素进行一一对应来命名.

比如:

NSArray *numberArray = @[@1, @2, @3, @4, @5 , @6, @7, @8, @9];

for (id number in numberArray) {

    NSLog(@"%@", number);
}

错误写法:

NSArray *numberArray = @[@1, @2, @3, @4, @5 , @6, @7, @8, @9];

for (id item in numberArray) {

    NSLog(@"%@", item);
}
NSArray *numberArray = @[@1, @2, @3, @4, @5 , @6, @7, @8, @9];

for (id abc in numberArray) {

    NSLog(@"%@", item);
}

布局框架

@(AutoLayout)[Masonry]


  • 在项目开发中, 我们经常会遇到View需要布局的情况, 通常我们会使用frame, size, center, bounds等属性去给View布局, 而且还需要我们给每个设备的屏幕一一对应的适配计算, 界面布局所花的代码量等同于业务的三分之一, 而且还不容易理解.

  • 但这个问题在2011之后就已经被解决了, 当时Apple引用了Cassowary constraint-solving算法, 并将这个算法命名为AutoLayout, 可以在绝大多数的情况下, 完美的解决屏幕适配的问题, 而且AutoLayout的黑魔法还不止于此, 想知道更多的同学可以去查查资料AutoLayout, 了解更多的黑魔法.

  • 随着Apple逐渐的完善, 许多iOS开发者纷纷推出了自己封装的AutoLayout库, 其中Masonry就是众多AutoLayout库之一, 为什么这里只推荐Masonry, 同学们自己去百度一下就明白了, 在GitHub里英文的使用手册, 如果你需要中文使用手册的话, 这里也可以提供Masonry中文使用手册

注意: 在工程中禁止使用Xib, 禁止在StoryBoard拖入任何控件, 且StoryBoard只可作为项目架构所使用.


文件夹层次结构

@(Project Framework)[MVVM]


MVC架构

MVC是一种使用MVC(Model View Controller 模型-视图-控制器), 有几大优点:

  • 耦合性低: 视图层和业务层分离,这样就允许更改视图层代码而不用重新编译模型和控制器代码,同样,一个应用的业务流程或者业务规则的改变只需要改动MVC的模型层即可。因为模型与控制器和视图相分离,所以很容易改变应用程序的数据层和业务规则。

  • 重用性高: 随着技术的不断进步,需要用越来越多的方式来访问应用程序。而MVC则可以在同一个模块下, 多个应用去访问, 不需要再去重写。

  • 生命周期成本低: MVC使开发和维护用户接口的技术含量降低。

  • 部署快: 使用MVC模式使开发时间得到相当大的缩减,它使程序员集中精力于业务逻辑,界面程序员集中精力于表现形式上。

  • 可维护性高: 分离视图层和业务逻辑层也使得应用更易于维护和修改。

  • 有利软件工程化管理: 由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化管理程序代码。

当然MVC也有它的缺点:

  • 没有明确的定义: 完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序带来了一定的困难。每个构件在使用之前都需要经过彻底的测试。

  • 不适合小型,中等规模的应用程序: 花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。

  • 增加系统结构和实现的复杂性: 对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

  • 视图与控制器间的过于紧密的连接: 视图与控制器是相互分离,但却是联系紧密的部件,视图没有控制器的存在,其应用是很有限的,反之亦然,这样就妨碍了他们的独立重用。

  • 视图对模型数据的低效率访问: 依据模型操作接口的不同,视图可能需要多次调用才能获得足够的显示数据。对未变化数据的不必要的频繁访问,也将损害操作性能。

  • 一般高级的界面工具或构造器不支持模式: 改造这些工具以适应MVC需要和建立分离的部件的代价是很高的,会造成MVC使用的困难。

结构图:
4


MVVM架构

MVVM模式和MVC模式一样,主要目的是分离视图View和模型Model,有几大优点

  • 低耦合: 视图View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

  • 可重用性: 你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。

  • 独立开发: 开发人员可以专注于业务逻辑和数据的开发ViewModel,设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成XAML代码。

  • 可测试: 界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

  • 结构: 通常MVVM架构图如图所示, 且开头首字母为大写

5 | center | 1080x0

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq350116542/article/details/51195386

智能推荐

打造健康产业新业态 中国抗衰老促进会康养产业分会成立-程序员宅基地

文章浏览阅读516次。6月23日,中国抗衰老促进会康养产业分会成立大会在京举行。原国家卫生部副部长孙隆椿、原总后卫生部部长李深、中国抗衰老促进会法人理事长刘仁富,副理事长朱怡霖、北京师范大学系..._中国抗衰老促进会证书含金量

How to use JFlash_jflash checksum-程序员宅基地

文章浏览阅读360次。 There is a problem happen when download firmware to the LPC2214 with JFlash v3.42b, the unit will not be turned on when power is on. But the download will be ok when I use JFlash v4.02 and v4.08, t_jflash checksum

Unity Texture2D的可读性问题_argumentexception: texture2d.getpixels: texture da-程序员宅基地

文章浏览阅读4.1k次。今天测试使用UMP播放网络摄像头的数据。处理截图的时候发现,显示摄像头图像的RawImage里面的图片保存不出来。研究了很久才发现这个时候里面的texture数据应该是不可读,所以直接使用EncodeToJPG()函数没有用。需要把这个Texture2D的数据转成可读的,方法如下// 复制出可读的Texture2D private Texture2D CopyT2DToWrite(Texture2D source) { // 先把Texture2D转成临时的_argumentexception: texture2d.getpixels: texture data is either not readable,

Error:kCFStreamErrorCodeKey=-2102 Domain=kCFErrorDomainCFNetwork Code=-1001 - iOS-程序员宅基地

文章浏览阅读7k次。之前早已调通的接口,因有新业务叠加新增了一些数据字段,之后再次调试接口的时候请求等待延迟至设定超时时间后出现了如下异常:[discovery] errors encountered while discovering extensions: Error Domain=PlugInKit Code=13 "query cancelled" U..._kcferrordomaincfnetwork code=-1001

汇编语言 十六进制转换为二进制_十六进制转二进制小程序-程序员宅基地

文章浏览阅读2.5w次,点赞26次,收藏148次。汇编语言程序,十六进制转换为二进制_十六进制转二进制小程序

51nod-1279 扔盘子_51nod - 1279-程序员宅基地

文章浏览阅读364次。1279 扔盘子题目来源: Codility基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题 收藏 关注有一口井,井的高度为N,每隔1个单位它的宽度有变化。现在从井口往下面扔圆盘,如果圆盘的宽度大于井在某个高度的宽度,则圆盘被卡住(恰好等于的话会下去)。盘子有几种命运:1、掉到井底。2、被卡住_51nod - 1279

随便推点

HikariCP常用监控指标与故障排查实战-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏7次。编者有言:本书由资深数据库连接池专家撰写,褚霸、德哥、张亮、吴晟等近10位专家高度评价,从设计思想、功能使用、原理实现、工程实践、技术扩展5个维度对HikariCP进行全面讲解和深入分析..._hikaricp 重连次数

mysql选择上一条、下一条数据记录,排序上移、下移、置顶_mysql上一条下一条功能实现-程序员宅基地

文章浏览阅读6.7k次。选择mysql记录上一条,下一条sql语句,完成列表排序上移,下移,置顶功能!设置一个rank为之间戳,通过选择上移,就是将本记录与上一条记录rank值交换,下移就是将本条记录与下一条记录rank值交换,置顶就是将本记录与rank值最小的记录交换_mysql上一条下一条功能实现

在本地浏览器上查看远程服务器上的tensorboard_访问tensorboard的url post-程序员宅基地

文章浏览阅读673次,点赞2次,收藏4次。1. keras中生成tensorboard日志信息 由于tensorboard日志是记录并且可视化训练过程的各个指标和权重信息的,所以需要通过回调函数来实现训练过程中的记录,然后将相应的回调函数传给模型的fit方法即可。如下所示,tf.keras.callbacks中有现成的回调函数,然后将其传给fit方法的callback参数即可。训练完成后就会在logdir目录下生成相应的信息文件。log_dir = "logs/fit/" + datetime.datetime.n..._访问tensorboard的url post

解决git冲突步骤(超详细)_git解决冲突-程序员宅基地

文章浏览阅读2.7w次,点赞10次,收藏112次。本文介绍git冲突产生原因,详细介绍两种冲突的解决步骤(图文详细说明),包括merge冲突、push/pull冲突两种冲突类型的详细解决步骤_git解决冲突

java项目日常运维需要的文档资料_项目运维文档-程序员宅基地

文章浏览阅读791次,点赞11次,收藏12次。java项目开发完成,部署上线,进入项目运维阶段,日常工作需要准备哪些资料和文档?当项目上线后,运行一段时间,或多或少会遇到一些运维上的问题,比如服务器磁盘饱满,服务器CPU,内存使用率过高,应用存在安全漏洞,应用报错,临时需求编个变更等等。诸多问题。那么若想快速响应,平时就需要准备好与项目运维相关的文档和资料。我总结了以下一些内容。_项目运维文档

【树(Tree)详细介绍】_树的应用场景-程序员宅基地

文章浏览阅读175次。树是一种重要的非线性数据结构,它具有层级关系,由一组以边连接的节点组成。树有许多不同的分类和应用场景,每种树的类型都有其特定的特点和用途。了解树的基本概念和常见的树的分类,有助于我们在实际问题中选择合适的数据结构和算法,提高程序的效率和性能。_树的应用场景

推荐文章

热门文章

相关标签