《Effective Objective-C 2.0》读书笔记(

2019-04-08  本文已影响0人  KeyboardDirver

第三章 接口与API的设置

第15条:用前缀避免命名空间冲突

命名空间冲突的表现

错误的原因在于,应用程序中的两份代码都各自实现了名为EOCTheClass的类,这导致EOCTheClass所对应的类符号和“元类”符号各定义了两次。比无法连接更糟糕的是,在运行期再入了含有重命名类的程序库。此时“动态加载器”(dynamic loader)就遭遇了“重名符号错误”(duplicate symbol error),很有可能会令整个应用程序崩溃。
苹果保留使用“两个字母前缀”(two-letter prefix)的权利,为了避免与苹果冲突推荐使用三个字母前缀,在函数命名时添加前缀不仅能减少命名冲突,同时在程序出错时的问题回溯中,也可以较为直观的发现问题所在地。

第16条:提供“全能初始化方法”

"全能初始化方法"(designated initializer) 常译为“指定出初始化方法”。为明确“designated”一词之含义,译文将其译成“全能”
有指定构造方法,当我们需要修改构造方法时就不必把每一个构造方法全都修改一遍,只需修改全能构造方法即可。

进入NSDate 文件

- (instancetype)init NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithTimeIntervalSinceReferenceDate:(NSTimeInterval)ti NS_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;

我们会发现NS_DESIGNATED_INITIALIZER 这个就是也就是指定构造方法。当自定义一个初始化方法时必须调用super的指定构造方法,不然

此外还有NS_UNAVAILABLE 如果在方法后著明那么在IDE的提示器中将不会出现此方法 此方法不可见
NS_UNAVAILABLE 和 NS_DESIGNATED_INITIALIZER

第17条:时间description方法

主要是这两个方法的使用 可以方便的自定义打印信息。在自定义的类中

-(NSString *)description;
- (NSString *)debugDescription;
第18条:尽量使用不可变对象

有一点要注意属性声明为readonly 也不是一定不可改的。 可以使用
1.kvc
2.直接使用类型信息查询功能查询出属性所对应的实例变量在内存布局中的偏移量,以此来认为设置这个实例变量的值。这样做是不符合公共API规范的。

第19条:使用清晰而协调的命名方式

方法命名规则:
1.如果方法的返回值时新创建的,那方法名的首个单词应该是返回值的类型,除前面有修饰语,例如localizedString。属性的存取方法不遵循着这种命名方式,因为一般认为这些方法不会创建新对象。即使有时返回内部对象的一份拷贝,我们也认为那相当于原有的对象。这些存取方法应该按照其所对应的属性来命名。
2.应该把表示参数类型的名词后面加上一个或多个名词。
3.若果方法要在当前对象上执行操作,那么就应该包含动词;若执行操作时还要参数,则应该在动词后面加上一个或者多个动词。
4.不要使用str这种简称,应该使用string这样的全称。
5.Boolean属性因该加is前缀。如果某方法返回非属性的Boolean值,那么应该根据其功能,选用has或is当前缀。
6.将get这个前缀留给那些借由“输出参数”来保存返回值的方法,比如说,把返回值填充到”C语言式数组”(C-style arrary)里的那种方法就可以使用这个词做前缀。

要点:

第20条:为私有方法名添加前缀

在项目中使用#param mark 对文件中的私有方法和公共方法进行分隔

第21条:理解Object-C错误模型
NSException exceptionWithName:<#(nonnull NSExceptionName)#> reason:<#(nullable NSString *)#> userInfo:<#(nullable NSDictionary *)#>

//可能会导致内存泄漏  详情见第30条

本条还举例说明使用error的二级指针来传递error对象的方法,注意在使用error解引用的时候必须保证 error参数不是nil 。 NSError* 存储的是指向NSError的指针。并不是NSError对象, *error取出的是NSerror * 是一个指针。

处理异常还可以使用

@try {
        <#Code that can potentially throw an exception#>
    } @catch (NSException *exception) {
        <#Handle an exception thrown in the @try block#>
    } @finally {
        <#Code that gets executed whether or not an exception is thrown#>
    }

或者断言NSAssert

要点

第22条:理解NSCopying协议

提到拷贝协议有NSCopying 和NSMutableCopying
还有就是深拷贝和前拷贝的问题了
首先要明确深拷贝和前拷贝的定义:
深拷贝:非容器类型(比如NSString)拷贝对象内存中的内从到新的内存中,如果是容器类型的(比如NSArray)会拷贝容器的外壳和容器中的内容。也就是把NSArray拷贝一份,数组中的对象也都拷贝一份。

浅拷贝:只是对对象的指针进行拷贝,内存中的内容没有进行拷贝(指针拷贝)。

在OC中的深拷贝是不完全的深拷贝,比如NSarray 使用mutableCopy只是拷贝了array的外壳深成了一个心的array地址,而数组中的对象并没有尽心深拷贝还是对象的地址并没有发生变化。网上关于深拷贝和前拷贝的文章5花8门,还是看书靠谱,有些写的不是很容易理解,对于深拷贝和前拷贝的没有明确的定义,有的文章比较片面,所以看技术文章要理性对待,实践才是检验真理的唯一标准。
若果嫌每个属性都进行拷贝比较麻烦可以利用runtime遍历属性进行 copy 这样可以在基类方法实现,方便子类调用。

要点

上一篇 下一篇

猜你喜欢

热点阅读