欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Effective Object-c 2.0 读书笔记

程序员文章站 2022-05-13 12:45:40
OC 的简单实用 1.在类的头文件中尽量少引用其他头文件 #import 和 @class 后者不需要知道类的全部细节,只是知道有一个类名叫XXX(避免循环饮用,两个类中有...

OC 的简单实用


1.在类的头文件中尽量少引用其他头文件

#import 和 @class 后者不需要知道类的全部细节,只是知道有一个类名叫XXX(避免循环饮用,两个类中有一个无法被正确编译) 向前声明(@class)能降低编译时间,还能降低彼此依赖程度

2.多用字面量语法,少用与之等价的方法

字面量数值
NSString *string = @"text";
NSNumber *number = @2.5;
NSNumber *boolNumber = @YES;

字面量数组(确保不能有nil)
NSSArray *animal = @["cat", "dog", "fish"];
NSSString *str = animal[1];

字面量字典(确保不能有nil)
NSDictionary *dic = @{@"key": @"Value",@"key1": @"Value1"}

3.多用类型常量,少用#define预处理指令

define ANIMATION_DURTION 0.3 static const NSTimerINterval KAnimationDurtion = 0.3(若只局限于编译单元前面?K,若全局通常以类名为前缀) 使用全局变量
    //XXX.h
    extern NSString *const xxxStringConstant
    // XXX.m
    NSString *const xxxStringConstant = @"Value"

4.用枚举表示状态、选项、状态码

状态机、选项卡 某个方法的选项定义为枚举类型,而多个选项又可以同时使用的,将各选项值定义为2的幂 处理枚举类型的switch语句不使用default分支

对象、消息、运行期


1.理解“属性”这一概念

getter、setter、autosynthesis(会在编译期执行合成方法)、synthesis(修改变量名:_xxx) copy(为了安全)、strong、weak、assign(简单赋值)、nonatomic、atomic(太耗性能)

2.在对象内部尽量直接访问实例变量

//xxx.h
@property (copy, nonatomic) NSString * firstName
Xcode会自动为你autosynthesis 生成相应get、set 方法

_firstName 是直接访问实例变量
self.firstName 是访问方法返回变量

3.理解”对象等同性”这一概念

若想检测对象的等同性
 - (BOOL)isequalToPerson:(Person *)otherPerson {
    if (self == otherPerson) return YES;
    if (!([_firstName isEqualToString:otherPerson.firstName])) {
        return  NO;
    }
    return  YES;
}
相同的对象必须具有相同的hash,但是两个哈希码相同的对象未必相同
hashcode本身就是个函数,是可以重载的,你完全可以写个函数总是返回固定值。但hashcode函数从设计要求上来说,要尽量保证:不同对象的hashcode不同。
尽量使用计算速度快而且哈希码碰撞几率低的算法

4.以”类族模式”隐藏实现细节(后续补充)

子类应该继承自类族中的抽象基类 子类应该定义自己的数据存储方式(?) 子类应该覆写超类文档中需指明需要覆写的方法 类族模式可以把实现细节隐藏在一套简单的公共接口后面 系统框架中经常使用类族 从类族的公共抽象基类中继承自类时要当心,若有开发文档,则应首先阅读

5.在即有类中使用关联对象存放自定义数据

(Runtime的使用)

OBJC_ASSOCIATION_ASSIGN
OBJC_ASSOCIATION_RETAIN_NONATOMIC
OBJC_ASSOCIATION_COPY_NONATOMIC
OBJC_ASSOCIATION_RETAIN
OBJC_ASSOCIATION_COPY

6.理解objc_msgSend的作用

消息由接受者、选择子及参数构成。给某对象”发送消息”(invoke a message),就相当于在该对象上”调用方法” 发给某对象的全部消息都要由”动态派发系统”来处理,该系统会查出对应的方法,并执行其代码。

7.理解消息转发机制

若对象无法响应某个选择子,则进入消息转发过程
 + (BOOL)resolveInstanceMethod:(SEL)sel {

    NSString *selectorString = NSStringFromSelector(sel);
    if ([selectorString hasPrefix:@"set"]) {
        class_addMethod(self, sel, (IMP)autoDictionarySetter, "v@:@");
    } else {
        class_addMethod(self, sel, (IMP)autoDictionaryGetter,"@ @:");
    }

    return  YES;
}

8.用”方法调配技术”调试”黑盒方法”

使用另一份实现来替换原有的方法实现 不宜乱用

9.理解”类对象”的用意

每个实例都有一个指向class对象的指针,用以表明其类型,而这些class对象则构成了累的继承体系 如果对象无法在编译器确定,那么就应使用类型方法来探知。 尽量使用类型查询方法。而不要直接比较对象,因为某些对象可能实现了消息转发功能(?)
isKindOfClass
isMemberOfClass
NSLog(@"%@",NSStringFromClass([NSDictionary class]));
//print : NSDictionary  
 NSLog(@"%@",NSStringFromClass([[NSMutableDictionary new]class]))
//print : __NSDictionaryM
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
    NSLog(@"%d,%d, %d",[dic isMemberOfClass:[NSDictionary class]], [dic isMemberOfClass:[NSMutableDictionary class]], [dic isMemberOfClass:NSClassFromString(@"__NSDictionaryM")]);
   输出 001

接口与API设计


1.用前缀避免命名空间冲突

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

2.提供”全能初始化方法”

在类中提供一个全能初始化方法,并于文档里指明。其他初始化方法均应调用此方法 若全能初始化方法与超类不同,则需要覆盖超类中的对应方法 若超类的初始化方法不适用于自类,那么应该覆写超类这个放啊。并在其中抛出异常
 - (instancetype)init {
    @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"必须使用 initFirstName:" userInfo:nil];
}

3.实现description方法

4.尽量使用不可变对象(??)

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

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

in、for、with、and、has、is 驼峰式(类的首字母要大写并且带前缀,方法首字母小写) 方法名要言简意赅,从左至右像是日常用语 方法不要带缩略后的类型名称

6.为私有方法名加前缀

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

7.理解Object-C的错误模型

只有发生了可使整个应用程序崩溃的严重错误时,才应使用异常 若错误不那么严重的话,可以将错误信息放在NSError对象里,经由”输出参数”返回给调用者

8.理解NSCopying协议

可变对象调用copy方法会返回一个不可变类的实例
不可变对象调用mutableCopy方法会反悔一个不可变版本
若想令自己所写的对象具有拷贝功能,则需实现NSCopying协议


协议和分类


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

if([_delegate resondsToSelector:@selector(xxx:xxx)]) {
do something
}
*更好的是使用struct*

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

使用分类机制把类的实现代码分成易于管理的小块 将应该视为”私有”的方法归入Private的分类中,以隐藏实现细节

3.总是为第三方类的分类名称加前缀(??)

向第三方类中添加分类,总应给其名称加上你专用的前缀 向第三方类中添加分类时,总应给其中的方法加上你专用的前缀

4.勿在分类中声明属性

把封装数据所用的全部属性都定义在主接口(如果是扩展NSObject,那就必须是Runtime) 在”class-continuation分类”之外的其它分类,可以定义存取方法,但尽量不要定义属性

5.使用”class-continuation分类” 隐藏实现细节

通过”class-continuation 分类”向类中新增实例变量 如果某属性在主接口申明为”只读”,可以在”class-continuation分类”将其扩展为”可读写” 把私有方法的原型申明在”class-continuation分类”里面 若想使类遵循的协议不为人知,则可于”class-continuation分类”中声明

6.通过协议提供匿名对象(??)

协议可在某种程度上提供匿名类型。具体的对象类型可以淡化成遵从某协议的ID类型,协议里规定了对象所应实现的方法 使用匿名对象来隐藏类型名称(或类名) 如果具体类型不重要,重要的对象能够响应(定义在协议里的)特定方法,那么可以使用匿名对象来表示