Effective oc 2.0 第三章学习--接口与API设计

接口与API设计

  • 用前缀避免命名空间冲突
    • 要点
  • 提供“全能初始化方法”
    • 要点
  • 实现description方法
    • 要点
  • 尽量使用不可变对象
    • 要点
  • 使用清晰协调的命名方式
    • 方法命名
    • 类与协议命名
    • 要点
  • 为私有方法名加前缀
    • 要点
  • 理解Objective-C错误模型
    • NSError对象封装的三条信息:
    • NSError用法
    • 要点
  • 理解NSCopying协议
    • 重写copy方法
    • copy和mutableCopy的区别
    • 深拷贝和浅拷贝的区别
    • 要点

用前缀避免命名空间冲突

oc没有其他语言那种内置的命名空间机制。如果出现重名,就会发生命名冲突。若是发生重名冲突,那么应用程序相应的链接过程就会出错,运行文件不知道究竟该调用那个文件,因为其中出现了重复的符号。

  • 解决这一问题的方法是为所有的名称都加上适当的前缀来变相实现命名空间
  • apple自身宣称其保留使用两字母前缀的权利,这意味着我们自身定义的名称前缀最好是两位字母以上的,如TWRequest
  • 不仅是类名,所有的名称,如类别名都应加上前缀
  • 为自己命名的名称无论如何都最好加上前缀,无论是调用第三方库还是上传第三方库,如果自己上传的第三方库中调用了其他第三方库,那么最好统一一下前缀

要点

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

提供“全能初始化方法”

“全能初始化方法”就是一个初始化方法,但是他的类创建对象的时候无论用什么初始化方法创建,其中代码都会调用某个初始化方法,那么这个初始化方法就是“全能初始化方法”。

到底该怎么初始化方法呢?

  • 重写初始化方法:首先需要在你新的初始化方法中的调用这个类的“全能初始化方法”,如果他是继承关系的话,那么就使用super来调用父类的初始化方法,调用完了之后你就可以编辑你自己的想要实现的初始化方法了。
    但是,有时候我们可能不想覆写超类的全能初始化方法,因为那样做没有道理,那么我们就可以覆写超类的全能初始化方法,让在调用这个方法的时候抛出异常,这样就可以确保用户一定使用的是你自己定义的方法了,但实际上意义不大 ;
  • 一个类有多个全能初始化方法要注意的问题:通常我们遇到的类都只有一个全能初始化方法,但是偶尔也有类具有多个全能初始化方法,例如:我们熟知的UI控件,通常我们都是使用代码来初始化的,但是我们还可以使用NIB拖动进行初始化,两种初始化解码的方法是不相同的。
  • 由于这两种初始化方法的解码方式不同,而且我们也不能人为的改变其解码的方式,那么我们就只能顺其自然,他有两种我们也重写两种初始化方法
  • 每个子类的全能初始化方法都应该调用其超类的对应方法

要点

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

实现description方法

我们在调试程序的的时候经常要打印并查看对象信息。此时我们就可以用到description方法,其实description就是对这个对象本身的描述。
在这里插入图片描述
description方法会生成描述信息
Effective oc 2.0 第三章学习--接口与API设计_第1张图片
如果是一个自定义的类,那么它就会输出该类的地址:
在这里插入图片描述

  • 只有在自己的类里覆写description方法,这个对象的描述才会改变,否则打印信息时就会调用NSObject类所实现的默认方法。
  • 在description方法中使用字典输出:在自定义的description方法中,把待打印的信息放到字典里面,然后将字典对象的description方法所输出的内容包含在字符串里并返回
    Effective oc 2.0 第三章学习--接口与API设计_第2张图片
    Effective oc 2.0 第三章学习--接口与API设计_第3张图片
    这样写的好处就是,可以令代码更易维护,并且如果你向该类中新增属性的话,你就在description方法中增加就行了。
  • debugDescription:和description差不多,就是描述的位置不一样,description是在函数调用类的时候触发方法才输出的,而debugDescription是在控制台中使用命令打印该对象时才调用的。

要点

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

尽量使用不可变对象

  • 不可变对象,这里指的是这个类里边的属性是不能直接被修改的,要实现这种功能,我们就需要用到我们的readonly修饰符。
    默认情况下,属性是readwrite(即可读又可写)的,这样修饰出来的类都是“可变的”。Effective oc 2.0 第三章学习--接口与API设计_第4张图片

有时可能想修改封装在对象内部的数据,但是却不想令这些数据为外人所改动。这种情况下,通常的做法是在对象内部将readonly属性重新声明为readwrite。当然,如果该属性是nonatomic的,那么这样做可能会产生“竞争条件”,即在对象内部写入某属性时,对象外的观察者也许正读取该属性。若想避免此问题,我们可以在必要时通过“派发队列”等手段,将(包括对象内部的)所有数据存取操作都设为同步操作。
不要在返回的对象上查询类型以确定其是否可变。

要点

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

使用清晰协调的命名方式

方法命名

如果方法的返口值是新创建的,那么方法名的首个词应是返回值的类型,除非前面还有修饰语,例如localizedString。属性的存取方法不遵循这种命名方式,因为一般认为这些方法不会创建新对象,即便有时返口内部对象的一份拷贝,我们也认为那相当手原有的对象。这些存取方法应该按照其所对应的属性来命名。

如果方法要在当前对象上执行操作,那么就应该包含动词;若执行操作时还需数,
则应该在动词后面加上一个或者多名词,不要使str这种简称,应该用 string 这样的全称。Boolean 属性应加is前级。如果某方法返口非属性的 Boolean 值,那么应该根据其功能,选用has 或is 当前缀。get这个前缀留给那些借由“输出” 参数,来保布返口值的方法

类与协议命名

应该为类与协议的名称加上前缀,以避免命名空间冲突,而且应该像给方法起名时那样把词句组织好,使其从左至右读起来较为通顺。基本命名规则就是:命名方式应该一致,如果要从其他的类中继承子类,那么就要遵守其原本的命名惯例。

要点

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

为私有方法名加前缀

通常我们在写方法时,并没有对其进行私有共有分类,导致调试时可能很麻烦,现在为私有方法加上前缀,这样便于修改方法或方法签名。具体加什么来代表私有方法因人而异,自己怎么舒服怎么来,唯一注意的是:一定不要只使用_作为前缀,用p_都比那个好,因为苹果公司使用的就是_作为私有方法的前缀的,你自己定义的私有方法名有可能就会和人家自带的冲突。

要点

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

理解Objective-C错误模型

“自动引用计数”在默认情况下不是“异常安全的”,就是说,如果抛出异常,那么本应该在作用域末尾释放的对象现在却不会释放了,这样就会造成内存泄漏问题,如果想生成“异常安全”的代码,可以通过设置编译器的标志来实现,不过这将引入一些额外的代码,在不抛出异常时,也照样要执行这部分代码。
OC语言现在所采用的办法是:只在极其罕见的情况下抛出异常,异常抛出之后,无须考虑恢复问题,而且应用程序此时也应该退出。这就是说,不用再编写复杂的“异常安全”代码了。在出现“不那么严重的错误”时,OC语言所用的编程范式为:令方法返回nil/0,或是使用NSError,以表明其中有错误发生。像我们之前都用过的网络请求,其中就使用到了NSError来表示错误。

NSError对象封装的三条信息:

Effective oc 2.0 第三章学习--接口与API设计_第5张图片

NSError用法

第一种常见就是通过委托协议传递这个错误,当前对象会把协议中的某个方法传给委托的对象,此方法常用于API的设计。

另一种常见用法是:经由方法的“输出参数”返回给调用者。就是说用一个方法来判断你传过去的error是否真的有错误,返回Boolean值,之后你就可以根据error是否有内容,或者Boolean值来决定处理的代码和不处理的代码
还可以为error参数“解引用(error所指的那个指针现在要指向一个新的NSError对象)”之前,必须先保证error参数不是nil,因为空指针解引用会导致段错误并使程序崩溃,所以注意要判断error是不是nil。

要点

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

理解NSCopying协议

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

- (id)copyWithZone:(NSZone *)zone;

为何会出现NSZone呢?
因为以前开发程序时,会据此把内存分成不同的“区”,而对象会创建在某个区里。现在不用了,每个程序只有一个区:“默认区”。所以说,尽管必须实现这个方法,到那时你不必担心其中的zone参数。
copy方法由NSObject实现,该方法只是以“默认区”为参数来调用“copyWithZone:”。

重写copy方法

Effective oc 2.0 第三章学习--接口与API设计_第6张图片

copy和mutableCopy的区别

无论当前实例是否可变,若需获取其可变版本的拷贝,均应调用mutableCopy方法,同理,若需要不可变的拷贝,则总应通过copy方法来获取。

拷贝方法称为copy而非immutableCopy的原因在于,NSCopying不仅设计给那些具有可变版本和不可变版本的类来使用,而且还要供其他一些类来使用,而那些类没有“可变”与“不可变”之分,所以说,把拷贝方法叫成immutableCopy不合适。

深拷贝和浅拷贝的区别

深拷贝:在拷贝对象自身时,将其底层数据也一并复制过去。
浅拷贝:在拷贝对象自身时,只拷贝容器对象本身,而不复制其中的数据。
Effective oc 2.0 第三章学习--接口与API设计_第7张图片

要点

  • 若想令自己所写的对象具有拷贝功能,则需实现NSCopying协议。
  • 如果自定义的对象分为可变版本和不可变版本,那么就要同时实现NSCopying与NSMutableCopying协议。
  • 复制对象时需决定采用浅拷贝还是深拷贝,一般情况下应该尽量执行浅拷贝。
  • 如果你所写的对象需要深拷贝,那么可考虑新增一个专门执行深拷贝的方法。

你可能感兴趣的:(学习,java,数据结构)