第二章 对象、消息、运行期
总结
1、属性特质
(1)、原子性:
atomic(默认);
nonatomic(开发中使用,提高程序的性能)
(2)、读写权限:
readwrite(拥有getter与setter方法);
readonly(仅getter方法)
(3)、内存管理语义:
assign(修饰“纯量类型-scalar type”,即基础类型,如:NSInteger);
strong(“拥有关系”,先保留新值并释放旧值,再将新值设置上去,属于“强引用”);
weak(“非拥有关系”,既不保留新值也不释放旧值,属于“弱引用”);
unsafe_unretained(与 assign的语义相同,但它适用于“对象类型”,不保留并且不安全);
copy(所属关系与strong类似,但设置方法不保留新值,而是拷贝其值,通常用来修饰NSString,保护其封装性)
(4)、方法名:
getter=<name> (指定“获取方法”的方法名,比如:@property(nomatomic, getter=isOn) BOOL on; )
setter=<name>(指定“设置方法”的方法名,不太常见)
2、在对象内部尽量直接访问实例变量
(1)在读取实例变量时采用直接访问的形式,而在设置实例变量时通过属性来做。
(2)在初始化方法及dealloc方法中,应该直接通过实例变量来读写数据。
(3)在使用“懒加载”的情况下,需要通过属性来读取数据。
3、以“类族模式”隐藏实现细节
比如:UIKit 中的UIButtton的类,类方法:+(UIButton *)buttonWithType:(UIButtonType)type;
如何创建“类族模式”:
第一步:定义抽象基类和子类的枚举类型
第二步:定义继承基类的子类
第三步:在基类里面提供公共接口----类方法:(如:+(Class基类)classWithType:(枚举Type)type; ,以其生成子类实例)
4、在既有类中使用关联对象存放自定义数据(runtime的应用--给已有的类添加属性)
▣ void objc_setAssociatedObject(id object, voidkey, id value, objc_AssociationPolicy policy); --- 设置关联对象值
▣ id objc_getAssociatedObject(id object, voidkey); --- 获取相应的关联对象值
▣ void objc_removeAssociatedObjects(id object); --- 移除对象的全部关联的对象
5、objc_msgSend的作用
原型:void objc_msgSend(id self, SEL cmd, ...)
说明:这是一个参数个数可变的函数(variadic function),能接受两个及两个以上的参数。第一个参数代表接收者,第二个参数代表选择子(即方法的名字),SEL是选择子的类型。该方法先寻找接收者所在类的方法,若没找到,沿着继承体系继续向上查找,若找到则跳转,否则执行”消息转发“操作。
其他特殊情况:
▣ objc_msgSend_stret:处理待发送的消息要返回结构体;
▣ objc_msgSend_fpret:处理待发送的消息要返回浮点型;
▣ objc_msgSendSuper:处理要给超类发送消息。
6、消息转发机制
在对象接收到无法解读的消息,就会启动”消息转发“机制,并将此消息转发给了NSObject的默认实现。分为两个阶段:
第一阶段:”动态方法解析(dynamic method resolution)“,即先征询接收者,所属的类,看能否动态添加方法,以处理当前这个”未知的选择子(unknown selector)“。首先将调用其所属类的下列类方法:
+ (BOOL) resolveInstanceMethod:(SEL)selector;
假如未实现的方法是类方法,则调用 + (BOOL)resolveClassMethod:(SEL)selector;
接收者还有第二次机处理未知的选择子,备援接收者是否能把这条消息转发其他接收者来处理,对应的处理方法如下:
- (id) forwardingTargetForSelector:(SEL)selector;
第二阶段:”完整的消息转发机制(full forwarding mechanism)“,首先创建NSInvocation的对象,把与尚未处理的那条消息有关的全部细节都封于其中。
1E1F75700F4A98076CB6C7445F6E9969.jpg
7、用”方法调配技术“ 调试 ”黑盒方法“(俗称:”黑魔法“)
”方法调配“(method swizzling)和 ”IMP“ 其原型:id (*IMP)(id, SEL, ...)
(1)、交换已经写好的方法实现:
void method_exchangeImplementations(Method m1, Method m2);
获取方法实现的函数:
Method class_getInstanceMethod(Class aClass, SEL aSelector);
注:1、在运行期,可以向类中新增或替换选择子所对应的方法实现;
2、使用另一份实现来替换原有的方法实现(向原有实现中添加新功能);
3、一般来说,只有调试程序的时候才需要在运行期修改方法实现,这种做法不宜滥用。
8、“类对象”的用意
每个类仅有一个“类对象”,而每个“类对象”仅有一个与之相关的“元类”。
typedef struct objc_class *Class;
struct objc_class {
Class isa;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
}
在类继承体系中查询类型信息
1、“isMemberOfClass:”能够判断出对象是否为某个特定类的实例,而“isKindOfClass:”则能够判断出对象是否为某类或其派生类的实例。例如:
NSMutableDictionary *dict = [NSMutableDictionary new];
[dict isMemberOfClass:[NSDictionary class]]; //输出 NO
[dict isMemberOfClass:[NSMutableDictionary class]]; //输出 YES
[dict isKindOfClass:[NSDictionary class]]; //输出 YES
[dict isKindOfClass:[NSArray class]]; //输出 NO