EFFECTIVE OBJECTIVE-C 2.0 TIPS 总结 CHAPTER 1 & CHAPTER 2
下面只是对读到的所有 Tips 结合我平时开发中遇到的问题进行总结,每一个 Tips 和书中的每一条对应,本文的目的是去掉书中的大部分讨论的内容,让人能够马上使用这些 Tips,建议阅读过原书后食用更佳。
CHAPTER 1 熟悉 OBJECTIVE-C
Tips 1 Objective-C 的起源
- Objective-C 是从 C 语言演化而来,有 C 的一些基础会有很大帮助
Tips 2 头文件中减少引用
- 减少在类的头文件中 import 其他头文件,如果使用其他类,那么使用
@class ClassName;来进行Forward Declaring - 对于协议,每个协议放到对应的头文件,使用时候引用
- 对于委托协议(比如
UITableView和UITableViewDelegate)因为只有与委托类放在一起才有意义,所以就不用单独分离头文件,应该放到定义UITableView的头文件中
- 减少在类的头文件中 import 其他头文件,如果使用其他类,那么使用
Tips 3 使用字面量
- 对于
NSString,NSNumber,NSDictionary和NSArray使用类似@"String",@1,@[]和@{}不要使用等价方法
- 对于
Tips 4 使用类型常量
定义常量时,使用类型常量不要使用
#define,比如:// 使用如下的方式定义
static const NSInteger kInteger = ;
// 而不是
#define SOME_INTEGER 1这样可以给编译器类型信息,在编译时和开发时能够进行类型检查
每一个 m 文件都是一个编译单元
使用
static声明表示在本编译单元有效,若需要将变量放到全局有效,那么需要使用extern使用
const表示常量不会被修改
Tips 5 使用枚举表示状态,选项,状态码
- 使用
NS\_ENUM宏定义枚举,因为枚举是按顺序的,也就是枚举值是1,2,3…… 这样的 - 使用
NS\_OPTION定义选项,因为选项是按位的,也就是选项是通过1 << 0,1 << 1这样来定义的,表示1右移
- 使用
CHAPTER 2 对象,消息,运行时
Tips 6 理解属性
使用属性,而不是实例变量,在代码中使用点(
.)操作符访问属性属性会生成对应的实例变量,一般是属性名前加下划线,也可以在类的实现代码中通过
@synthesize来指定,例如:@synthesize firstName = _firstName使用
@dynamic告诉编译器不需要生成对应的getter 和 setter属性的 attribute 会影响编译器生成的代码
atomic / nonatomic,原子性,一般我们都使用
nonatomic因为 iOS 的属性锁开销很大,另外atomic并不能保证线程安全readwrite / readonly,读写或是只读
内存管理要注意的
- assign,简单类型直接赋值
- strong,表示持有
- weak,不持有,在对象被释放时属性将会变成
nil - unsafe_unretained,不持有,在对象被释放时属性不会变成
nil - copy,设置属性时会调用对象的
-copy方法获得新的对象,建议所有不可变的NSString,NSArray,NSDictionary都使用这个方法,可变的类型不可以使用这个方法 - getter=name / setter=name,指定 getter 和 setter 方法的名字
Tips 7 对象内部直接访问实例变量,设置时通过属性方法
- 直接访问实例变量减少方法调用消耗
- 设置通过属性方法,调用实际的 setter,能够保证写入控制和 KVO 的触发
- 可以在 getter 和 setter 方法中加入断点方便调试
- 惰性初始化的变量,因为需要需要重写 getter 方法,所以不能使用直接访问实例变量来访问
Tips 8 对象相等
==只是比较对象指针是否相等,深层的比较需要使用-isEqual:方法- 如果
-isEqual:返回返回真,那他们的-hash方法要返回同一个值,但是-hash方法返回同一个值的两个对象-isEqual:不一定为真 -hash方法用作在集合类型中计算索引,如果所有对象的这个方法都返回同一个值,那么在集合中检索对象性能会很差,这个方法应该使用计算速度快,并且不容易碰撞的方法实现- 有特定相等判断方法的对象,优先使用特定相等判断方法,可以减少调用次数和对对象进行类型检查(例如
NSString的-isEqualToString:方法) - 放入集合对象中的对象,需要保证
-hash方法得到的值不会变,如果放入集合后,修改集合内对象导致-hash的值发生变化,那么集合对象是不会知道-hash值有变化,并且将来会出现奇怪的错误
Tips 9 类簇
- 类簇很有用,可以把实现细节隐藏在抽象的基类中
- 对于使用到类簇的对象,需要使用
-isKindOfClass:来判断,不可使用[object class] == [Class class]或者-isMemberOfClass:来判断 - 若要继承类簇中的类,那么需要根据文档实现对应的方法
Tips 10 Associated Object
可以为已有的对象创建新的属性
设置方法
void objc\_setAssociatedObject(id object, void *key, id value, objc\_AssociationPolicy policy)id objc\_getAssociatedObject(id object, void *key)id objc\_removeAssociatedObject(id object)
关联类型和属性的对应(上面 policy 的值)
- OBJC_ASSOCIATION_ASSIGN:assign
- OBJC_ASSOCIATION_RETAIN_NONATOMIC:nonatomic, retain
- OBJC_ASSOCIATION_RETAIN:retain
- OBJC_ASSOCIATION_COPY_NONATOMIC:nonatomic, copy
- OBJC_ASSOCIATION_COPY:copy
key 的值,使用一个 opaque pointer,一般来说使用静态全局变量
Tips 11 理解
objc\_msgSend的作用Objective-C 中所有的方法,都是 C 函数
给某个对象的消息全部都是动态发送的,如下
id returnValue = [someObject messageName:parameter]- 编译后,将会使用
objc\_msgSend函数处理消息发送,得到id returnValue = objc_msgSend(someObject, @selector(messageName:), parameter) objc\_msgSend会去someObject的方法列表中对应的函数,如果找不到,那么沿着继承体系继续找,还是找不到,那么会进行消息转发操作(在 Tips 12 讲解)
Objective-C 的运行时已经做了很多保证让这套机制性能很好
- 其中一个优化就是尾调用优化,Objective-C 的每个对象的方法都是 C 方法,并且有和
objc\_msgSend一样的原型,这样在objc\_msgSend从对象的方法列表中找到对应函数时,可以直接跳转过去,不需要重新在调用堆栈中插入新的栈帧
- 其中一个优化就是尾调用优化,Objective-C 的每个对象的方法都是 C 方法,并且有和
Tips 12 理解消息转发
因为 Objective-C 使用运行时来决定具体调用的方法,所以在运行之前是不知道一个对象是否能响应特点方法的
消息转发是在一个对象收到无法解读的消息时触发的机制
消息转发的过程
- 第一步,进行动态方法解析——询问接收者,所属的类,看是否能动态添加方法,来处理未知的 selector
- 第二步,第一步无法处理这个 selector 的话进行消息转发——首先,让接收者看看是否有对象能处理这个消息,如果有,那么丢给他处理;如果没有,那么运行时会把所有和消息相关的东西放到一个
NSInvocation对象里面,最后再给接收者一次处理的机会
动态方法解析
过程,下面两个过程是渐进的,第一个失败了,那么执行第二个
- 调用
+ (BOOL)resolveInstanceMethod:(SEL)selector询问类是否能新增一个实例方法处理这个消息 - 调用
+ (BOOL)resolveClassMethod:(SEL)selector询问类是否能增加一个类方法来处理这个消息
- 调用
用法,相关方法实现已经写好,只等着运行时去动态插入到类里面就行了
- 实现
@dynamic属性
- 实现
消息转发
备选的消息接收者
- 调用
- (id)forwardingTargetForSelector:(SEL)selector询问接收者是否有另一个对象来处理这个消息 - 可以模拟多重继承,由对象内的其他对象来处理这个消息,但是从调用者看来,是被调用的对象处理的消息
- 这样转发的消息,我们是无法进行操作或是修改消息内容的
- 调用
完整的消息转发
- 创建
NSInvocation对象,把 selector,target 和参数都放进去 - 消息派发系统(message-dispatch system)调用
- (void)forwardInvocation:(NSInvocation *)invocation方法吧消息指派给目标对象 - 这个方法可以简单的只修改接收者让另一个对象去接受处理这个方法,但是这样做法和使用备选的消息接收者做法是等效的,所以一般来说更多是先修改消息内容,再触发消息
- 这个方法的如果没有实现,那么就会调用超类的这个方法,类的继承体系中的所有类都有机会处理直到
NSObject NSObject的- (void)forwardInvocation:(NSInvocation *)invocation只是简单的调用- (void)doesNotRecognizeSelector:方法抛出异常,所以一般向对象发送他没有实现的方法都会通过这个方法抛出异常
- 创建
Tips 13 Method Swizzling(原书叫方法调配技术,看到这个名词,第一句话是什么鬼)
很多时候,这个技术被大家称为黑魔法,但是其实他做的只是在运行时交换方法的实现而已
所有的方法都是在对象中是一个
IMP指针,指针原型id (*IMP)(id, SEL, ...)每个类通过一张映射表来映射可相应的 selector 和对应
IMP指针的关系可以做 AOP
对方法的操作
使用
void method_exchangeImplementations(Method m1, Method m2)来交换两个方法使用
Method class_getInstanceMethod(Class aClass, SEL aSelector)来获取类的实例方法常规的 Method Swizzling 做法
// 在 Category 的定义文件中增加我们将要用来替换的方法
@interface NSString (MethodSwizzling)
- (NSString *)ms_myLowercaseString;
@end // 在 Category 的实现文件中,进行交换
@implementation NSString (MethodSwizzling)
- (NSString *)ms_myLowercaseString {
// 在调用原方法前做点其他的事情
// 注意这里并不是递归调用,而是因为我们交换了 lowercaseString 和 ms_myLowercaseString 的实现,所以这里调用 ms_myLowercaseString 实际上是在调用 lowercaseString 方法
NSString *s = [self ms_myLowercaseString]; // 在调用完原方法后做点其他的事情
return s;
} + (void)load {
Method m1 = class_getInstanceMethod([NSString class], @selector(lowercaseString));
Method m2 = class_getInstanceMethod([NSString class], @selector(ms_myLowercaseString));
method_exchangeImplementations(m1, m2);
}
@end
Tips 14 理解类对象
- 每个对象结构体的首个成员变量是
Class类的变量 Class对象是一个objc_class的结构体,里面保存了类的元数据Class类同样有元类(metaclass)- 某个类如果有超类(super class)那么他的
Class对象的元类,也继承于该类超类的元类 -isMemberOfClass:可以判断某个对象是否是某个类的实例-isKindOfClass:可以判断某个对象是否是某个类或其子类的实例- 使用上面说到的两个方法类判断类型,不要直接比较类对象,因为某些对象可能实现了消息装发功能
- 每个对象结构体的首个成员变量是
EFFECTIVE OBJECTIVE-C 2.0 TIPS 总结 CHAPTER 1 & CHAPTER 2的更多相关文章
- Effective Objective-C 2.0 Tips 总结 Chapter 3 & Chapter 4
Chapter 3 接口与 API 设计 Tips 15 使用前缀避免明明空间冲突 Objective-C 没有命名空间,所以我们在起名时要设法避免命名冲突 避免命名冲突的方法就是使用前缀 应用中的所 ...
- 阅读《Effective Java》每条tips的理解和总结(1)
<Effective Java>这本书的结构是90来条tips,有长有短,每条tip都值的学习.这里根据对书中每条tip的理解做简短的总结,方便日后回顾.持续更新~ 1. 考虑用静态方法代 ...
- iOS开发——技术精华Swift篇&Swift 2.0和Objective-C2.0混编之第三方框架的使用
swift 语言是苹果公司在2014年的WWDC大会上发布的全新的编程语言.Swift语言继承了C语言以及Objective-C的特性,且克服了C语言的兼容性问题.Swift语言采用安全编程模式,且引 ...
- 执行sudo时报错:effective uid is not 0
http://jingyan.baidu.com/article/c45ad29cd83d4b051753e232.html 今天将 / 授权给了一个普通用户 导致一些问题. 启事: 操作前一 ...
- [svc]执行sudo时报错:effective uid is not 0
http://jingyan.baidu.com/article/c45ad29cd83d4b051753e232.html 今天将 / 授权给了一个普通用户 导致一些问题. 启事: 操作前一定要先在 ...
- 阅读《Effective Java》每条tips的理解和总结(2)(持续更新)
15. 使类和成员的可访问性最小化 一个好用的类的属性必须要隐藏起来,干净的将它与类的api分离开来,类之间只通过api相互使用,降低他们之间的耦合性.为了做到这一点,建议根据情况选择尽可能低的访问级 ...
- Journal entry of the eighth chapter to chapter ten
Chapter eight: 当我们做一个项目的时候,一开始可能会信息满满,或者说是通过一些调查分析后觉得自己的团队能完全实现用户所提出的所有要求,但是,往往在很自信的时候,我们都会处处碰壁,因为组内 ...
- Journal entry of the thirteenth chapter to chapter seventeenth(第十三章和十七章阅读与疑问)
第十三章: 软件测试的意义在于: a. 发现软件错误: b. 有效定义和实现软件成分由低层到高层的组装过程: c. 验证软件是否满足任务书和系统定义文档所规定的技术要求: d. ...
- Journal entry of the eleventh chapter to chapter twelfth
第十一章:正如很多人一样,觉得软件工程这个课程好像没什么用,感觉提高不了自己的写代码能力,学的都是理论知识,好像对于我们这种技术类的专业离得有点远,是这样的吗? 第十二章:每样东西都没有完美的,即使我 ...
随机推荐
- simplefactory简单工厂模式
简单工厂模式概述 又叫静态工厂方法模式,它定义一个具体的工厂类负责一些类的实例 优点 客户端不需要在负责对象的创建,从而明确了各个类的职责 缺点: 这个静态工厂类负责所有对象的创建, ...
- 学习java之利用泛型访问自己定义的类
如果有多个类,而且他们其中有一些方法是相同的,我是选择在每个类中都把这些方法实现一遍呢,还是选择泛型.我今天自己花了一点时间看了看泛型,实践了一下. Holder.java package regex ...
- erl0005 - mnesia 分布式部署
http://www.iteye.com/topic/643187 1.启动两个互通的节点a.b: 2.在a节点net_adm:ping(b) 查看ab之间是否联通(nodes()). 3.在保持通的 ...
- PS常用
一.文字和背景居中 1.按Ctrl+A或用矩形框选中所有 2.按选择工具->在工具属性栏里面会显示6种方向的对齐方式 二.画准确铺助线 1.视图->新建参考线->输入数值既可
- ecshop lib包含lib文件
在lbi文件中增加lbi方法 方法1. {include file='library/name.lbi '} 方法2. <?php echo $this->fetch('library/n ...
- 《C++ Primer 4th》读书笔记 序
注:本系列读书笔记是博主写作于两三年前的,所以是基于<C++ Primer>第四版的,目前该书已更新至第五版,第五版是基于C++11标准的,貌似更新挺多的.博主今年应届硕士毕业,如若过阵子 ...
- 前端程序员:月薪 5K 到 5 万,我干了啥(转)
转自:http://www.imooc.com/article/4110 前端程序员:月薪 5K 到 5 万,我干了啥前端开发工作已经变的越来越复杂,仅仅是想罗列一份前端开发的学习列表就已经是一件艰巨 ...
- 在python中如何设置当前工作目录
import osos.chdir('要设置的当前目录') >>> import os >>> os.getcwd() 'D:\\Python27' >> ...
- android性能小贴士 翻译
转自http://developer.android.com/training/articles/perf-tips.html 性能小贴士: 这篇文档主要一些微优化可以提升应用程序性能,但是这些改变不 ...
- myeclipse svn配置
在MyEclipse 9.0中安装SVN插件遇到一些问题,参考网上一些方法,最终解决.以下是个人认为比较简易的方法,供参考: 安装过程: (1)svn的插件版本site-1.8.14.zip(可根据自 ...