effective OC2.0 阅读笔记 (三 接口与API设计)

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

为什么要避免命名空间冲突?

Objective-C没有其他语言那种内置的命名空间 (namespace) 机制.在应用开发时,所有的代码和引用的静态库最终都会被编译到同一个域和二进制中。这样的后果是一旦我们有重复的类名的话,就会导致编译时的冲突和失败。

避免命名冲突

  1. 变相实现命名空间:为所有名称都加上适当前缀。
  2. 使用Cocoa创建应用程序时一定要注意,Apple宣称其保留使用所有“两字母前缀”(two-letter-prefix)的权利,所以我们选用的前缀最好是三个字母的。
  3. 不仅是类名,应用程序中的所有名称都应加前缀,包括分类以及分类方法。
  4. 在类的实现文件中,所用的纯C函数以及全局变量,在编译好的目标文件中,是要算作“顶级符号”(top-level-symbol)的。
  5. 可以参考之前static(当static关键字修饰局部变量时,只会初始化一次。),如果不加static,在两个.m文件中声明同一个string 变量,会冲突报错。
  6. 使用第三方库A编写自己的代码,并准备将其发布为程序库B供他人开发程序所用,此时应该给所用的那一份第三方库A代码都加上自己的前缀。(现在一般使用Cocoapods来管理第三方,这种第三方库冲突就很少见了)

要点

  1. 选择与公司、应用程序或二者皆有关联之名称作为类名的前缀,并在所有代码中均使用这一前缀。

  2. 若自己所开发的程序库中用到了第三方库,则应为其中的名称加上前缀。

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

所有对象均要初始化。

可为对象提供必要信息以便其能完成工作的初始化方法叫做“全能初始化方法”(designated initializer, 也常译为:“指定初始化方法”)。

初始化方法可以调用全能初始化方法来实现(一个类可以有多个)。于是,只有在全能初始化方法中,才会存储内部数据。这样的话,当底层数据存储机制改变时,只需要修改此方法就好,无需改动其他初始化方法。

要点:

  • 在类中提供一个全能初始化方法,并于文档里指明。其他初始化方法均应调用此方法。

  • 全能初始化方法的调用链一定要维系。每个子类的全能初始化方法都应该调用其超类的对应方法,并逐层向上。

  • 全能初始化方法超类不同,则需覆写超类中的对应方法。

  • 如果超类的初始化方法不适用于子类,那么应该覆写这个超类方法,并在其中抛出异常。(超类的初始化方法是为子类服务的?)

第17条:实现description方法

什么是description方法?

description是所有类都有的一个方法。
我们重写这个方法,可以自定义实例输出的信息。
比如我们可以创建一个Person类:
在.h文件中添加两个属性

#import
@interfacePerson : NSObject
@property (strong, nonatomic) NSString*name;
@property (assign, nonatomic)intage;
@end

在.m文件中重写description方法:

#import"Person.h"
@implementationPerson
- (NSString *)description
{
return[NSString stringWithFormat:@"<%p> - name: %@, age: %d", self, _name, _age];
}
@end

通过主函数进行调用

Person *person =[[Person alloc] init];
person.name=@"XiaoMing";
person.age=28;
NSLog(@"person - %@", person);

此时控制台会有输出:

person - <0x7fa20bc18d10> - name: XiaoMing, age:28

如果在.m文件中没有重写description方法,则输出结果为:

person - <0x7fa20bc18d10> 

此方法定义在NSObject协议里,不过NSObject类也实现了它。因为NSObject并不是唯一的“根类”,所以许多方法都要定义在NSObject协议里。比方说,NSProxy也是一个遵从了NSObject协议的“根类”。由于description等方法定义在NSObject协议里,因此像NSProxy这种“根类”及其子类也必须实现它们。

这就是这个方法的作用 所以当我们在自己的类中想要输出信息,就要覆写description方法

要点:

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

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

  1. 声明对外属性时,尽量使用不可变对象,同时,对外属性声明里尽量加上readonly修饰(默认是readwrite修饰)。这样外部只能读取数据而不能修改数据,保证了这个类的实例所持有的数据更加安全。尤其是不要把可变的collection作为属性公开,而是应该提供相应的方法修改可变的collection。
  2. 若外部想修改修改对象的值有两种途径:
  • 提供接口方法修改
  • 使用KVC(Key-Value Coding)技术
    这种技术允许对象的数据或属性可以在运行时通过其键名进行查找,其中,属性的名称即为其值的键名。在静态语言中,这样的做法是不可能的。KVC大大的增加了设计的自由度:通过KVC,无需知道对象的类型即可访问其属性或数据。

例如 :

不推荐写法:

//Animals.h
@property (nonatomic, strong) NSSet *animals;

应改为:

//Animals.h
@interface Animals : NSObject

@property (nonatomic, strong, readonly) NSSet *animals;

- (void)addAnimal:(NSString *)animal;
- (void)removeAnimal:(NSString *)animal;

@end


//Animals.m
@implementation Animals {
    NSMutableSet *_mutableAnimals;
}

- (NSSet *)animals {
    return [_mutableAnimals copy];
}

- (void)addAnimal:(NSString *)animal {
    [_mutableAnimals addObject:animal];
}

- (void)removeAnimal:(NSString *)animal {
    [_mutableAnimals removeObject:animal];
}

这样写固然有好处:保证了数据的安全性,但代码量也会提升不少。所以推荐大家可以有选择的使用,对一些重要的类才有使用必要。

要点

  • 声明对外属性时,尽量创建不可变的对象

  • 若某属性仅可于对象内部修改,则在“class-continuation分类”中将其由readonly属性扩展为readwrite属性也可以在.h文件中把属性声明为readonly,在.m文件中通过实例变量修改值,当block内部修改值时,可以用self->实例变量的方法访问修改。

  • 不要把可变的collection作为属性公开,而应提供相关方法,以此修改对象中的可变collection

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

方法与变量名整体上的规则

  • 方法与变量名使用了“驼峰命名”,以小写字母开头,其后每个单词首字母大写。类名也用驼峰命名发,不过其首字母需要大些。

方法命名时的规则

  • 如果方法的返回值是新创建的,那么方法名的首个词应是返回值类型,除非前面还有修饰语,例如localizedString。属性的存取方法不遵循这种命名方式,因为一般认为这些方法不会创建新的对象,即便有时返回内部对象的一份拷贝,我们也认为那相当于原有的对象。
  • 应该把表示参数类型的名词放在参数前面。
  • 如果方法要在当前对象上执行操作,那么就应该包含动词;若执行操作时还需要参数,就在动词后面加上一个或多个名词。
  • 不要使用str这种简称
  • Boolean属性应该加is前缀。如果某方法返回非属性的Boolean值,那么应该根据其功能,选用has或is前缀。
  • 由“输入输出”来保存返回值的方法用get前缀。

类与协议的命名

命名方式应该协调一致。如果从其他框架中继承子类,那么务必遵循其命名惯例,例如,继承自UIView的自定义子类,那么累名末尾的词必须是view

要点

  • 起名时应遵从标准的Objective-C命名规范,这样创建出来的接口更容易为开发者所理解。
  • 方法名要言简意赅。
  • 方法名里不要使用缩略后的类型名称。

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

一个类所做的事情通常都要比从外面看到的更多。编写类的实现代码时,经常要写一些只在内部使用的方法。应该为这些方法的名称加上某些前缀,这样有如下好处

  • 有助于调试,因为据此可以很容易地把公有方法和私有方法区分。
  • 便于修改方法名或方法签名。对于公共方法来说,修改了其名称或签名,那么使用这个类的所有其他代码都得更新才行。而对于内部方法来说,若要修改其签名或名称,则只需同时修改本类内部的相关代码即可,不会影响面向外界的API。

要点:

  • 给私有方法的名称加上前缀,可以区分公有方法和私有方法。

  • 不要单用一个下划线作为私有方法的前缀。因为这种做法是预留给苹果公司的。

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

后续有博客 关于ARC与错误模型的

要点

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

第22条:理解NSCopying协议

[iOS开发]深拷贝与浅拷贝

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值