effective OC2.0 52阅读笔记(二 对象、消息、运行期)
第二章:对象、消息、运行期
6 理解属性这一概念
总结:OC解决硬编码偏移量问题的做法,一种方案是把实例变量当做一种存储偏移量所用的特殊变量,交由类对象保管,偏移量会在运行期查找,叫做稳固的“应用程序二进制接口”ABI。二种方案是使用存取方法访问实例变量。属性的访问方法由编译器在编译期执行,并且编译器还会自动向类中添加实例变量。
eg:如果从core data的框架中的NSManagedObject类里继承一个子类,就需要在运行期动态创建存取方法。因为子类的某些属性不是实例变量,其数据来自后端的数据库中。
@interface EOCPerson:NSManagedObject
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation EOCPerson
@dynamic firstName,lastName;//编译器在此时不会自动合成存取方法或实例变量。
@end
属性特质可以分为四类,原子性,读/写权限,内存管理语义(只要实现属性所用的对象是可变的,就应该在设置新属性值时拷贝一份) 方法名@property(nonatomic,getter=isOn) BOOL on;
实现自定义的初始化方法时,一定要遵循属性定义中宣称的“copy”语义,_first = [firstName copy];使用于别的内存管理语义。
注意:不应该在init方法中调用存取方法;应该尽可能使用不可变对象。
7 在对象内部尽量直接访问实例变量
总结:建议在读取实例变量的时候采用直接访问形式,而在设置实例变量的时候通过属性来做。
两种做法区别:直接访问实例变量速度快,编译器所生成的代码会直接访问保存对象实例变量的那块内存。但会绕过为相关属性定义的内存管理语义。不会触发键值观测。通过属性访问有助于排查相关错误。
通过设置方法写入实例变量时需要注意,在初始化方法中及dealloc方法中应该直接访问实例变量,对于初始化方法是因为子类可能会复写设置方法。在基类的默认初始化方法中,可能会将姓氏设为空字符串。此时若是通过设置方法来做,那么调用的将会是子类的设置方法,从而抛出异常。
- (void)setLastName:(NSString *)lastName
{
if(![lastName isEqualToString:@"smith"]){
[NSException raise:NSInvalidArgumentException format:@"Last name must be Smith"];
}
self.lastName = lastName;
}
另外:当要惰性初始化的时候,必须通过获取方法来访问属性,否则,实例变量就永远不会初始化。
8 理解“对象等同性”这一概念
总结:判断等同性的两个关键方法:- (BOOL)isEqual:(id)object; - (NSUInteger)hash;编写hash方法时,应该用当前的对象做做实验,以便在减少碰撞频度与降低运算复杂程度之间取舍。有时候判断等同性可以根据特有的标识符,就像主键一样。放入容器中的对象不应再改变,例如把某个对象放入set之后又修改其内容,那么后面的行为将很难预料。相同的对象必须具有相同的哈希码,但是两个哈希码相同的对象未必相同。不要盲目地逐个检测每条属性,而是应该依照具体需求来制定检测方案。编写hash方法时,应该使用计算速度快而且哈希码碰撞几率低的算法。
9 以类族模式隐藏实现细节
总结:类族模式可以把实现细节隐藏在一套简单的公共接口后面。工厂模式是创建类族的办法之一。Cocoa系统框架中大部分collection类都是类族。例如:用NSArray的alloc方法获取实例时,该方法首先会分配一个属于某类的实例,此实例充当“占位数组”。该数组稍后会转为另一个类的实例,而那个类则是NSArray的实体子类。当向类族中新增实体子类时,对于Employee这个例子来说,若是没有工厂方法的源代码,就无法向其中新增雇员类别了。然而对于NSArray这样的类族来说,还是有办法增加子类的,但是从类族的公共抽象积累中继承子类时要当心,若有开发文档,应先阅读。
10 在既有类中使用关联对象存放自定义数据
总结:有时需要在对象中存放相关信息,但是该类的实例可能是由某种机制所创建的,而我们无法令这种机制创建出自己缩写的子类实例。就要用关联对象(associated object)来解决这个问题。objc_setAssociatedObject(object,void *key,id value,objc_AssociationPolicy),objc_getAssociatedObject(object,key),objc_removeAssociatedObjects(object)。类似于NSDictionary,设置关联对象时用的键是不透明指针(opaque pointer),如果在两个键上调用isEqual方法的返回值是YES,那么NSDictionary就认为而这项等。然后在设置关联对象时,若想令两个键匹配到同一个值,则二者必须是完全相同的指针才行。所以设置关联对象值时,通常使用静态全局变量做键。只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的bug。
11 理解objc_msgSend的作用
总结:边界情况(特殊情况),objc_msgSend_stret返回结构体,objc_msgSend_fpret返回浮点数,objc_msgSendSuper。尾调用优化技术:如果某函数的最后一项操作是调用另外一个函数,而不会将其返回值另作他用时,才能执行“尾调用优化”。只保留内层函数的调用记录,如果所有函数都是尾调用,那么完全可以做到每次执行时,调用记录只有一项,这将大大节省内存。消息由接收者,选择子及参数构成。给某对象发送消息,也就相当于在该对象上调用方法。发给某对象的全部消息都要有动态消息派发系统来处理,该系统会查出对应的方法,并执行其代码。
12 理解消息转发机制
总结:消息转发分为两大阶段,一动态方法解析:先征询接收者,所述的类,看能否添加动态方法;二完整的消息转发机制:先看有没有其他对象能处理这条消息。若没有则启动完整的消息转发机制,运行期系统会把与消息有关的全部细节都封装到NSInvocation对象中。
+ (BOOL)resolveInstanceMethod:(SEL)selector;(尚未实现的是实例方法调用这个方法)
+(BOOL)resolveClassMethod:(SEL)selector;(尚未实现的是类方法)
用+ (BOOL)resolveInstanceMethod:(SEL)selector实现@dynamic属性
return YES;或者是return [super resovleInstanceMethod:selector];动态添加方法
- (id)forwardingTargetForSelector:(SEL)selector;可以模拟出多重继承的某些特性,但是无法操作由这一步所转发的消息。
- (void)forwardInvocation:(NSInvocation*)invocation;一是改变调用目标,但是与上一步效果等效。二是出发消息前,先以某种方式改变消息内容,追加另外一个参数,或是改换选择子。
CALayer是兼容与键值编码的容器类,就是说,能够向里面随意添加属性,然后以键值对的形式来访问。属性值的存储工作由基类直接负责,我们只需在CALayer的子类中定义新属性即可。
若对象无法响应某个选择子,则进入消息转发流程。通过运行期的动态方法解析功能,我们可以在需要用到某个方法时再将其加入类中。对象可以把其无法解读的某些选择子转交给其他对象来处理。经过上述两步之后,如果还是没有办法处理选择子,那就启动完整的消息转发机制。
13 用方法调配技术调试黑盒方法
总结:交换方法用void method_exchangeImplementations(Method m1,Method m2);方法实现用Method class_getInstanceMethod(class aClass,SEL aSelector)。通过此方案,可以为那些完全不知道其具体实现的黑盒方法增加日志记录功能,有助于程序调试。但若滥用,会使代码变得不易读懂且难于维护。
14 理解类对象的用意
总结:在程序中不要直接比较对象所属的类,明智的做法是调用类型信息查询方法,isKindOfClass和isMemberOfClass,也可用比较类对象是否等同的办法来做。若是如此,就要使用==操作符,不要用isEqual,因为类对象是单利,在应用程序范围内,每个类的Class仅有一个实例。每个类仅有一个类对象,所以可以使用==,而每个类对象仅有一个与之相关的元类。尽量使用类型信息查询方法来确定对象类型,而不要直接比较对象,因为某些对象可能实现了消息转发功能,如果用直接比较的方法class返回的对象和查出来的类对象是不同的,class方法所返回的类表示发起代理的对象,而非接受代理的对象。
effective OC2.0 52阅读笔记(二 对象、消息、运行期)的更多相关文章
- effective OC2.0 52阅读笔记(七 系统框架)
47 熟悉系统框架 总结:将代码封装为动态库,并提供接口的头文件,就是框架.平时的三方应用都用静态库(因为iOS应用程序不允许在其中包含动态库),并不是真正的框架,然而也经常视为框架.例如:NSLin ...
- effective OC2.0 52阅读笔记(五 内存管理)
第五章:内存管理 29 理解引用计数 30 以ARC简化引用计数 总结:ARC通过命名约定将内存管理规则标准化.其他编程语言很少像OC这样强调命名.ARC通过设置全局数据结构(此数据结构的具体内容因处 ...
- effective OC2.0 52阅读笔记(一 熟悉Objective-C)
第一章:熟悉Objective-C 1 了解objective-c语言的起源 总结:OC为C语言添加了面向对象的特性,是其超集.采用动态绑定的消息结构而非函数调用,也就是说,要在运行时才检查对象类型及 ...
- effective OC2.0 52阅读笔记(六 块与大中枢派发)
派发队列:dispatch_queue 操作队列:NSOperationQueue 组:dispathc_group_t 37 理解“块”这一概念 总结:块就是一个值,且自有其相关类型.块的强大之处 ...
- effective OC2.0 52阅读笔记(三 接口与API设计)
第三章:接口与API设计 15 用前缀避免命名空间冲突 总结:避免重名符号错误的唯一办法是变相实现命名空间.为所有符号都加上命名前缀.类和分类都应加三字前缀.注意类实现文件中的纯C函数及全局变量,是算 ...
- effective OC2.0 52阅读笔记(四 协议与分类)
23 通过委托与数据源协议进行对象间通信 总结:委托模式的常规委托模式中,信息从类Class流向受委托者delegate.数据源模式,信息从数据源datasource流向class.数据源和受委托者可 ...
- iOS 52个技巧学习心得笔记 第二章 对象 , 消息, 运行期
1. 属性 在开发过程中经常要用到定义属性,@property和@synthesize是经常用到的属性, property在.h文件中作声明,@synthesize在.m文件中用于实现 // Stud ...
- 《Java编程思想》阅读笔记二
Java编程思想 这是一个通过对<Java编程思想>(Think in java)进行阅读同时对java内容查漏补缺的系列.一些基础的知识不会被罗列出来,这里只会列出一些程序员经常会忽略或 ...
- Java Jdk1.8 HashMap源代码阅读笔记二
三.源代码阅读 3.元素包括containsKey(Object key) /** * Returns <tt>true</tt> if this map contains a ...
随机推荐
- ASP.NET MVC Razor语法
ASP.NET MVC Razor语法 (一) 关于_ViewStart.cshtml文件 使用Razor模板引擎的话,会自动生成一个_ViewStart.cshtml文件.事实上,_View ...
- jquery 获取和设置 checkbox radio 和 select option的值?
============== 获取和设置 checkbox radio 和 select的值? === val()函数, 其名字就表达了 它的意思: 他就是= value 的简写! val就是valu ...
- matlab求解相关系数
最近收到一项新任务,要求两个矩阵的相关系数,说白了就是转换成向量两两计算.本来这个工作我是想自己写个小程序搞定的,但是大家纷纷反映matlab自带了此项功能,本着活到老学到老的心态,我开始查找这个函数 ...
- JS抽奖功能代码
HTML <label for="awardListDom">奖项列表</label><br> <input type="tex ...
- Java 中浮点数---------BigDecimal和double(初探)
为什么要使用 bigdecimal? 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了 ...
- JAVA浅析字节流与字符流
[概括] 字节流是通用的,既可以操作图片又可以操作文本,但一般都用于操作图片.字符流是基于字节流的,因为字符流内部融合编码表,所以用来操作文本. 1.在字节输入流中能根据文件的大小来开辟数组空间 Fi ...
- LYDSY模拟赛day3 涂色游戏
/* 非常好的题 */ #include <cstdio> #include <iostream> #include <cstdlib> #include < ...
- 大型网站SEO优化策略框架
- laravel中间件-----------middleware
middleware中间件 是访问到达服务器后在被对应的路由处理之前所经过的一层过滤层,故称中间件. 中间件是存放在app\http\middleware中,需要定一个 handle 处理方法,在ha ...
- UNIX Time 时间戳 与 北京时间 相互转换
typedef struct t_xtime { int year; int month; int day; int hour; int minute; int second; } _xtime ; ...