首页 Effective Objective-C 2.0 读书笔记5
文章
取消

Effective Objective-C 2.0 读书笔记5

第3章 接口与API设计

将接口设计成易于复用的形式,便于重用代码。

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

1
2
3
4
5
6
7
// 错误原因:应用程序中两份代码都是些类xxx类
duplicate symbol_OBJC_METACLASS_$_xxx in:
	build/xx.o
	bulid/xx_else.o
duplicate symbol_OBJC_CLASS_$_xxx in:
	build/xx.o
	build/xx_else.o

Objective-C没有内置的命名空间机制。起名时需要设法避免潜在的命名冲突,否则重命名导致应用程序崩溃,避免此问题的唯一方法是变相实现命名空间:为所有名称都加上适当的前缀。

易忽视引发命名冲突的地方,是类实现文件中所用的纯C函数及全局变量

要点:

  • 选择与你的公司、应用程序或二者皆有关联之名称作为类名的前缀,并在所有代码中均使用这一前缀
  • 若自己所开发的程序库中用到类第三方库,则应为其中的名称加上前缀

第16条:提供“指定初始化方法”

所有对象都要初始化。

指定初始化方法:为对象提供必要信息以便其能完成工作的初始化方法

  • 类的初始化方法可能不止一个,要在其中选定一个作为指定初始化方法,令其他初始化方法都调用它。
  • 只有在指定初始化方法中,才会存储内部数据。当底层数据存储机制改变时,只需修改此方法的代码,无需修改其他初始化方法
  • 如果子类的指定初始化方法与超类的方法的名称不同,那么总应该覆写超类的指定初始化方法。
  • 每个子类的指定初始化方法都应该调用其超类的对应方法,并逐层向上。

要点

  • 在类中提供一个指定初始化方法,并于文档里指明。其他初始化方法均应调用此方法
  • 若全能初始化方法与超类不同,则需覆写超类中对应的方法
  • 若超类的初始化方法不适用于子类,那么应覆写那个超类方法,并在其中抛出异常

第17条:实现description方法

调试程序时打印并查看对象信息。

  • 借助NSDictionary类的description方法,可以在description中输出很多互不相同的信息。{key:value;key2:value2}
    • 在自定义的description方法中,把待打印的信息放到字典里面,然后将字典对象的description方法所输出的内容包含在字符串里并返回

要点

  • 要实现description方法返回一个有意义的字符串,用以描述该实例
  • 若想在调试时打印出更详尽的对象描述信息,则应实现debugDescription方法。

第18条:尽量使用不可变对象

设计类时,充分运用属性来封装数据,使用属性时,声明为“只读”,默认情况为“可读可写”。 把可变对象放入collection中又修改其内容,容易破坏set的内部数据结构,使其失去固定语义。减少对象中可变内容。

应该尽量把对外公布的属性设为只读,且只在确有必要时才将属性对外公布。

要想修改封装在对象内部的数据,又不想令其为外人改动。通常在对象内部将readonly属性重新声明为readwrite。

要点

  • 尽量创建不可变对象
  • 若某属性仅可用于对象内部修改,则在“Class-continuation分类”中将其由readonly属性扩展为readwrite属性
  • 不要把可变的collection作为属性公开,而应提供相关方法,以此修改对象中的可变collection

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

方法命名

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

类与协议的命名

应该为类与协议的名称加上前缀,以避免命名空间冲突,而且应该像给方法起名时那样把词句组织好,使其从左至右读起来较为通顺。

命名方式要协调一致。从其他框架中继承子类,务必遵循其命名惯例。

要点

  • 起名时应遵从标准的Objective-C命名规范,这样创建出来的接口更容易为开发者所理解
  • 方法名要言简意赅,从左至右读起来要像个日常用语中的句子才好
  • 方法名里不要使用缩略后的类型名称
  • 给方法起名时的第一要务就是确保其风格与自己的代码或所要集成的框架相符

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

为私有方法加上前缀,便于区分公共方法与私有方法;便于修改方法名或方法签名

要点

  • 给私有方法的名称加上前缀,这样可以很容易地将其同公共方法区分开
  • 不要单用一个下划线做私有方法的前缀,因为这种做法时预留给苹果公司用的。

第21条:理解Objective-C错误模型

  • 只有在极其罕见的情况下抛出异常,异常抛出之后,无需考虑恢复问题,而且应用程序此时也应该退出。
  • 非致命错误:令方法返回nil/0,或使用NSError,以表明错误发生
    • NSError对象封装类三条信息,把导致错误的原因回报给调用者
      • Error domain(错误范围,其类型为字符串)
      • Error code (错误码,其类型为整数)
      • User info(用户信息,其类型为字典)
    • NSError的用法
      • 通过委托协议来传递此错误
      • 经由方法的“输出参数”返回给调用者

要点

  • 只有发生可使整个应用程序崩溃的严重错误时,才应使用异常
  • 在错误不那么严重的情况下,可以指派“委托方法”来处理错误,也可以把错误信息放在NSError对象里,经由“输出参数”返回给调用者

第22条:理解NSCopying协议

使用对象时经常需要拷贝它。Objective-C中通过copy完成。如果想令自己的类支持拷贝操作,那么就要实现NSCopying协议。

无论当前实例是否可变,若需获取其可变版本的拷贝,均应调用mutableCopy方法;若需获取其不可变版本的拷贝,均应调用copy方法。

把拷贝方法称为copy而飞immutableCopy的原因:NSCopying不仅设计给那些具有可变与不可变版本的类使用,而且还要提供其他一些类使用,而那些类没有可变 与不可变之分。

深拷贝在拷贝对象自身时,将其底层数据也一并复制过去。Foundation框架中所有collection类在默认情况下都执行浅拷贝。拷贝之后的内容是原始对象中相关对象的一份拷贝

浅拷贝拷贝之后的内容与原内容指向相同对象。只拷贝容器对象本身,而不复制其中数据。因为,容器内的对象未必都能拷贝,而调用者也未必想拷贝容器的时候拷贝每个对象

要点

  • 若想令自己所写的对象具有拷贝功能,则需要实现NSCopying协议
  • 若自定义对象分为可变版本与不可变版本,那么就要同时实现NSCopying与NSMutableCopying协议
  • 复制对象时决定采用浅拷贝还是深拷贝,一般情况下尽量执行浅拷贝
  • 如果所写的对象需要深拷贝,那么可考虑新值一个专门执行深拷贝的方法
本文由作者按照 CC BY 4.0 进行授权