《Effective Objective-C》阅读笔记(中)

目录

接口与API设计

用前缀避免命名空间冲突

提供"全能初始化方法"

实现description方法

尽量使用不可变对象

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

方法命名

​编辑类与协议命名

为私有方法名加前缀

理解OC错误模型

理解NSCopying协议

协议与分类

通过委托与数据源协议进行对象间通信

将类的实现代码分散到便于管理的数个分类之中

总是为第三方类的分类名称加前缀

​使用"class-continuation分类"隐藏实现细节

通过协议提供匿名对象


接口与API设计

用前缀避免命名空间冲突

为了避免"重名符号错误",应当为所有名称都加上适当前缀,可以与公司、程序或二者皆有关。

但使用Cocoa创建程序时,要注意Apple保留使用所有"两字母前缀"的权利,所以开发者使用的前缀应该是三个字母的

不仅是类,还有C函数的名字也应加上前缀

如果是开发第三方库,那么对于所有包含的第三方库代码都加上自己的前缀。

提供"全能初始化方法"

可以为对象提供必要信息以便其能完成工作的初始化方法叫做"全能初始化方法"。

在上图方法中,initWithTimeIntervalSinceReferenceDate:便是全能初始化方法。

当一个类有多个初始化方法时,仍要选定一个作为全能初始化方法,其他初始化方法都调用它。

只有在全能初始化方法中,才会存储内部数据,这样的话,当底层数据存储机制改变时,只需修改此方法的代码就好。

如果子类的全能初始化方法与超类方法的名称不同,那么总应覆写超类的全能初始化方法。

实现description方法

在自定义类中,description的默认实现是打印类名和地址,输出信息如下:

这时我们应尽量将输出信息改为一个有意义的字符串,用来描述这个实例。有个简单的方法,就是借助NSDictionary的description方法。此方法输出的信息的格式如下:

字符串可以采用如下格式:

若想在调试时打印更详尽的描述信息,应实现debugDescripption方法。

尽量使用不可变对象

在编程实践中,应该尽量把对外公布出来的属性设为只读,而只在确有必要时才将属性对外公布。

有时可能想修改封装在对象内部的数据,但是不想让这些数据为外人所改动,这种情况下通常做法是将readonly重新声明为readwrite,这一操作应该在"class-continuation分类"中完成。

在定义类的公共API时,还应注意:对象里表示各种collection的那些属性应该设成可变的,还是不可变的。

比如:我们用某个类来表示个人信息,该类中还存放了一些引用指向此人的朋友,开发者可以添加或删除朋友,那这个属性就要用可变的set来实现。这种情况下,通常应该提供一个readonly属性供外界使用,返回一个不可变的set,这个set是内部可变set的一份拷贝。比如下面这份代码:

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

OC当中方法与变量名采用"驼峰式大小写命名法",而类名首字母大写,并且有两三个前缀字母。

方法命名

命名方法时,应当使方法像个日常用语中的句子,准确传达方法所执行的任务,然而方法名不能长得太过分,应尽量言简意赅。

类与协议命名

类与协议的名称应加上前缀,并且应该像给方法起名一样组织好词句,使从左至右比较通顺。

为私有方法名加前缀

在编写私有方法时,最好使用前缀将私有方法标注出来,前缀最好包含下划线与字母p。

要注意不应该直接使用下划线作为私有方法的前缀,因为苹果公司喜欢单用一个下划线作为私有方法的前缀,使用一个下划线有可能会无意中覆写超类中的其他方法。

理解OC错误模型

自动引用计数不是"异常安全"的,并且即使不用ARC,也很难写出在抛出异常时不会导致内存泄漏的代码。所以OC语言当中,异常只用于极其严重的错误,抛出异常之后,应用程序应该退出,也就无需考虑恢复问题了

在出现不那么严重的错误时,OC语言所用的编程范式为:令方法返回nil/0,或是使用NSError,以表明其中有错误发生。

NSError的用法更加灵活,NSError对象里封装了三条信息:

Error domain:错误发生的范围,也就是产生错误的根源。

Error code:独有的错误代码,用以指明在某个范围内具体发生了何种错误。

User info:有关此错误的额外信息。

NSError有两种常见用法,一种是通过委托协议来传递错误,另一种是经由方法的"输出参数"返回给调用者。

理解NSCopying协议

OC中如果想令自己的类支持拷贝操作,那就要实现NSCopying协议,该协议只有一个方法:

这里zone参数不用考虑,使用默认参数即可。比如游客表示个人信息的类,可以声明遵从NSCopying协议:

有时需要获取可变的拷贝,则应遵守NSMutableCopying协议,该协议也只定义了一个方法:

当对象需要深拷贝时,可考虑吧新增一个专门执行深拷贝的方法

协议与分类

通过委托与数据源协议进行对象间通信

OC开发中经常使用一种"委托模式",主旨是:定义一套接口,某对象若想接受另一个对象的委托,则需遵从此接口,以成为其"委托对象",而这另一个对象,则可以给其委托对象回传一些信息,也可以在发生相关事件时通知委托对象。一般通过协议来实现委托模式。

用一张图来演示委托模式的概念:

这里EOCDataModel1就是作为EOCNetwirkFetcher的委托对象。

但是要注意,类中存放委托对象的属性需定义成weak,而非strong:

objectivec 复制代码
@interface EOCNetworkFetcher : NSObject
@property (nonatomic, weak) id <EOCNetworkFetcherDelegate> delegate;
@end

因为通常delegate要持有本对象,若本对象也持有delegate,那么就会引入保留环。

实现委托对象可以在接口中声明,也可以在"class-continuation分类"中声明。如果要向外界公布此类实现了某协议,那么就在接口中声明,如果是委托协议,通常只在类内部使用,一般在"class-continuation分类"里声明。

还有另一种,令某类经由协议中接口获取所需的数据,被称为"数据源模式"。

若有必要,可实现含有位段的结构体,将委托对象是否能相应相关协议方法这一信息缓存至其中。

将类的实现代码分散到便于管理的数个分类之中

当类中存在大量方法的代码时,可以通过OC的分类机制,把类代码按逻辑划入几个分区中。

比如下面这个管理个人信息的类:

可以把不同的方法放入不同分类中:

这些分类可以全部放在一个实现文件中,但当存在许多分类时,最好每个分类提取到各自的文件中去。以EOCPerson为例,可以拆分成下列这几个文件:

私有方法应归入名叫Private的分类中,以隐藏实现细节。

总是为第三方类的分类名称加前缀

我们经常通过分类为无源码的既有类添加方法,这时就容易出现命名冲突的问题。我们应该为分类和方法添加了前缀。

比如为NSString添加分类处理HTTP URL有关的字符串。

我们为其加上前缀:

使用"class-continuation分类"隐藏实现细节

class-continuation分类"和普通的分类不同,他必须定义在其所接续的那个类的实现文件里,这是唯一能声明实例变量的分类。

这种分类在实现文件中格式如下:

通过这种分类可以获得隐藏程度更好的私有方法和私有变量。

除了获得隐藏变量和方法之外,使用这种分类还可以将只读的属性扩展为可读写的,以便在类的内部设置其值。

还有一种用法是,当对象所遵从的协议只应视为私有,则可在该分类中声明

通过协议提供匿名对象

有时,我们可以把返回的对象设计为遵从某协议的id类型 ,这样的话,想要隐藏的类名就不会出现在API之中了。若接口背后有多个不同的实现类,又不想指明具体使用哪个,可以考虑用这个方法,此概念被称为"匿名对象"。

有时对象类型不重要,重要的是有没有实现某些方法,在此情况下,也可以使用这些"匿名类型"来表达这一概念。

比如对受委托者的定义:

相关推荐
做怪小疯子4 分钟前
跟着李沐老师学习深度学习(十四)
人工智能·深度学习·学习
学学睡觉13 分钟前
Python学习总结
开发语言·python·学习
s_little_monster1 小时前
【Linux】缓冲区和文件系统
linux·运维·服务器·经验分享·笔记·学习·学习方法
StickToForever1 小时前
第5章 软件工程(二)
经验分享·笔记·学习·职场和发展
StickToForever1 小时前
第5章 软件工程(一)
经验分享·笔记·学习·职场和发展
愚戏师1 小时前
从零到一学习c++(基础篇--筑基期十一-类)
开发语言·数据结构·c++·学习·算法
程序员yt1 小时前
双非本南邮硕电子信息研一转码:优先掌握哪些编程语言?与学习路径推荐
qt·学习·考研
Magnetic_h2 小时前
《Effective Objective-C》阅读笔记(下)
笔记·ios·objective-c
Magnetic_h2 小时前
《Effective Objective-C》阅读笔记(上)
笔记·学习·macos·ios·objective-c·cocoa
一直走下去-明2 小时前
next.js-学习2
开发语言·javascript·学习