第三章 接口与API设计(EffectiveObjective-C)

1 使用前缀避免命名空间冲突

  • 命名冲突,应用程序链接的时候会报错
    duplicate symbol _OBJC_METACLASS_$_EOCTheClass in: build/somthing.o
    在运行期载入了含有重名类的程序库,"动态加载"遭遇"重名符号错误",会导致程序崩溃
  • 不仅是类名,应用程序中的所有名称都应加前缀,如果要为既有类新增"分类"(category),那么一定要给"分类"及"分类"中的方法加上前缀
  • 如果用第三方库编写自己的代码,并准备将其发布为程序库供其他人开发应用程序所用.
    这是应该给你所用的那一份第三非苦代码加上你自己的前缀.
    例如:你准备发布的程序库叫做EOCLibrary.

2 提供"全能初始化方法"

为对象提供必要信息以便其完成工作的初始化方法叫做"全能初始化方法"
UITableViewCell,在初始化该类对象时,需要指明其样式以及标识符
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier
如果创建类实例的方式不止一个,那么这个累就会有很多个初始化方法,不过仍然要在其中选定一个作为全能初始化方法,令其他初始化方法都来调用他
好处:当底层数据存储机制改变时,只需修改此方法的代码就好,无须改变其他初始化方法

3 现实description方法

description:在NSObject协议中,自定义NSLog方法返回的字符串
debugDescription:在NSObject协议中,自定义在控制台通过po命令输出的的字符串

4 尽量使用不可变对象

  • 设计类的时候,应充分应用属性来封装数据,而在使用属性时,则可将其声明为"只读"(read-only).
    默认情况属性是"可读可写"(read-write).这样设计出来的类是"可变的".
    在编程实践中,则应该尽量把对外公布出来的属性设为只读,而且只在确有必要时才将属性对外公布
@interface EOCPointOfInterest : NSObject
@property (nonatomic, copy,readonly) NSString *indentifier;
@property (nonatomic, copy,readonly) NSString *title;
@end
  • 有时可能想要修改封装在对象内部的数据,但是却不想令这些数据为外人所改动.这个时候,通常做饭是在对象内部将readOnly属性重新什么为readwrite,当然属性是nonatomic的,那么这样做可能会产生"竞争条件"(race condition).可以通过"派发队列"等手段,讲数据存取设为同步操作
#import "EOCPointOfInterest.h"
@interfaceEOCPointOfInterest ()
@property (nonatomic, copy,readwrite) NSString *indentifier;
@property (nonatomic, copy,readwrite) NSString *title;
@end

@implementation EOCPointOfInterest
@end
  • 不要把可变的collection作为属性公开,而应该提供相关方法,以此修改对象中的可变collection
    Person有个friends的集合属性
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong,readonly) NSSet *friends;
- (void)addFriend:(Person*)person;
- (void)removeFriend:(Person*)person;
@end

@implementation Person{    
  NSMutableSet *_internalFriends;
}

- (NSSet *)friends{    
  return [_internalFriendscopy];
}
- (void)addFriend:(Person *)person{   
    [_internalFriendsaddObject:person];
}
- (void)removeFriend:(Person *)person{ 
   [_internalFriendsremoveObject:person];
}
@end

5 使用清晰而协调的命名方式

方法与变量名使用"驼峰式大小写命名法",变量名小写字母开头,其后每个单词首字母大写
类名首字母要大写,其后每个单词首字母大写.
5.1 方法命名

  • 如果方法的返回值是新创建的,那么方法名的首个词应该是返回值类型,除非前面还有修饰语
  • 应该把标识参数类型的名词放在参数前面
  • 如果方法要在当前对象上执行操作,那么就应该包含动词,若执行操作时还需要参数,则应该在动词
    后面加上一个或多个名词
  • 不要使用str这种简称,应该用string这样的全称
  • Boolean属性应加is当前缀.如果某方法返回非属性的Boolean值,那么应该根据其功能选用
    has或is做前缀
  • 将get这个前缀留给哪些借由"输出参数"来保存返回值的方法.

5.2 类与协议的命名
应该为类与协议的名称加上前缀,以避免命名控件冲突

6 为私有方法名加前缀

  • 一个类所做的事情通常都要比从外面看到的更多,编写类的实现代码时,经常要写一些只有内部使用
    的方法,建议为这种方法的名称加上某些前缀, 这样有助于调试, 这样能很容易把公共与私有方法分开
  • 为私有方法添加前缀的好处二:修改其名称或签名之前要三思,公共API不便轻易改动(影响面广)
  • 具体使用何种前缀根据个人喜好,其中最好包含下划线与字母, 如p_作为前缀
@interface EOCObject : NSObject
- (void)publicMethod;
@end
@implementation EOCObject
- (void)publicMethod{}
- (void)p_privateMthod{}
@end
  • 不要单用一个下划线做私有方法的前缀,因为这种做法是预留给苹果的

7 理解Objective-C 错误类型

7.1 Objective-C:只在极其严重的错误下抛出异常,抛出异常之后,无需考虑回复问题,而且应用程序此时也应该退出
7.2 在非致命错误:Objective-C所采用的方式是令方法返回nil/0. 或是使用NSError,以表明其中有错误发生
7.3 NSError对象里封装了三条消息

  • Error domain:错误范围,也就是产生错误的根源.类型为字符串,通常用一个特有的全局变量来定义
  • Error code:错误码,类型为这个整数.用意指明具体发生了何种错误,通常采用enum来定义
  • User info:用户信息,类型为字典,关于错误的额外描述,包含一段"本地化描述"
    NSError第一种常见用法就是通过协议,来传递错误.有错误发生时,当前对象会把错误信息经由协议中的某个方法传递给委托对象(delegate)
    NSError第二种常见用法:经由方法的"输出参数"返回给调用者.
- (BOOL)doSomething:(NSError *__autoreleasing *)error{
  //do somethong that may cause an error   
 if (/*there was an error*/) {
        if (error) {
          *error = [NSErrorerrorWithDomain:domaincode:codeuserInfo:userInfo];
        }        
      returnNO;  
  }   
   returnYES;
}

传递给方法的参数是个指针,而该指针本事又指向另外一个指针,而该指针本身又指向另外一个指针,
那个指针指向NSError对象,或者也可以把他当成一个直接指向NSError对象的指针.这样一来,就可以经由
"输出参数"把NSError对象传递给调用者

NSError *error=nil;
[selfdoSomething:&error];

8 理解NSCoping协议

如果想自己的类支持拷贝操作,那就要实现NSCopying协议,该协议只有一个方法
- (id)copyWithZone:(NSZone *)zone;
long long age,会据此把内存分成不同的"区"(zone),而对象会创建在某个区里面,现在每个程序只有一个去,
"默认区"(default zone).所以在实现这个方法的时候,不用考虑参数zone.

你可能感兴趣的:(第三章 接口与API设计(EffectiveObjective-C))