一、KVO
1、当对象中的某个属性值发生了改变,可以对这些值的观察者做出通知。
2、接受者(会接收到值发生改变的消息) 必须知道发送者(值将发生改变的那个对象)。
3、接收者同样还需要知道发送者的生命周期,因为在销毁发送者对象之前,需要取消观察者的注册。
二、KVC
1、简介
a) 允许访问 property 的时候使用 string(key) 去标示 property(类型可以为 object || 基本数据类型)。
b) 在运行时才确定给哪个 property 赋值,则使用。
valueForKey: @"key"
setValue:forKey:
2、获取一个对象的所有 property name and value
#import <objc/runtime.h> unsigned int outCount, i; objc_property_t *properties = class_copyPropertyList([YourObject class], &outCount); for (i = 0; i < outCount; i++) { objc_property_t property = properties[i]; NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property)]; id propertyValue = [yourObject valueForKey:(NSString *)propertyName]; NSLog(@"Key = %@ Value = %@", propertyName, propertyValue); }
free(properties);
3、获取类的所有 private 成员变量的 name and type
#import <objc/runtime.h> Ivar *vars = class_copyIvarList([YourObject class], &varCount); for (int i = 0; i < varCount; i++) { Ivar var = vars[i]; const char* name = ivar_getName(var); const char* typeEncoding = ivar_getTypeEncoding(var); NSLog(@"Key = %s Value = %s", name, typeEncoding); } free(vars);
4、扩展
a) 通常 Server 返回 Json,最好的做法是返回一个 property 结构和 Json 结构一致的类。例如,
// json file [ { "Name": "AAA", "Age": 11 }, { "Name": "BBB", "Age": 22 } ] // Person.h @property(nonatomic, strong) NSString* name; @property(nonatomic, assign) NSInteger age; - (id)initWithDictionary:(NSDictionary*)jsonObject; - (NSString*)print; // person.m - (id)initWithDictionary:(NSDictionary*)jsonObject { self = [super init]; if (self) { [self setValuesForKeysWithDictionary:jsonObject]; } return self; }
b) 如果 json 中的 key值 和 property name 不一致,需要重载如下的方法,分别对不匹配的 property 赋值
- (void)setValue:(id)value forUndefinedKey:(NSString *)key { if ([key isEqualToString:@"id"]) self.identifier = value; else if ([key isEqualToString:@"Tel"]) self.telephone = value; else [super setValue:value forKey:key]; }
c) 对于内嵌 json 也转换为自定义对象, 需要重载下面的方法,对特殊的 key 做处理
// json file { "id": "001", "Name": "Eileen", "Age": 25, "Tel": "123456", "Purchase": [ { "ProductName": "Apple", "Price": 45 }, { "ProductName": "Pear", "Price": 100 } ] }, // People.m - (void)setValue:(id)value forKey:(NSString *)key { if ([key isEqualToString:@"Purchase"]) { for (NSDictionary* eachProductDict in value) { Product* eachProduct = [[Product alloc] initWithDictionary:eachProductDict]; [self.purchase addObject:eachProduct]; } } else [super setValue:value forKey:key]; }
d) valueForKeyPath 传递关系 (DSL 参考文章)
一般用在 NSArray 和 NSSet
Note: It is not currently possible to define your own collection operators.
// 返回 name 首字母为大写的数组 NSArray* array = [personObjList valueForKeyPath:@"name.capitalizedString"];// collection oprator
// 算法运算符 @sum @min @max @avg @count
NSNumber* sumOfAge = [personObjList valueForKeyPath:@"@sum.age"];
[array valueForKeyPath:@"@count"]
[array valueForKeyPath:@"@max.self"];
// array: @distinctUnionOfArrays, @unionOffArrays (array1, array2 里面元素对比)
[@[set1, set2]valueForKeyPath:@"@distinctUnionOfSets.self"]
[@[set1, set2]valueForKeyPath:@"@unionOfSets.self"]
三、Notification
1、在不相关的两部分代码中要想进行消息传递。
2、通知可以用来发送任意的消息。
3、发送者和接收者双方并不需要相互知道。这种消息传递机制是单向的,作为接收者是不可以回复消息的。
四、Delegate
1、定制某个对象的行为,并且可以收到某些确定的事件。
2、消息的发送者需要知道消息的接收者(delegate),反过来就不用了。
3、可以通过返回值的形式给发送者做出回应。
注意:过渡使用delegation也有一定的风险,如果两个对象的耦合程度比较紧密,相互之间不能独立存在,那么此时就没有必要使用delegate协议了,针对这种情况,对象之间可以知道相互间的类型,进而直接进行消息传递。
五、Block
1、block可以满足用delegation实现的消息传递机制。
2、如果为了让代码可读性更强,更有连贯性,那最好是使用block了。block经常可以用于completion handler、error handler等。
六、Target-Action
1、Target-Action主要被用于响应用户界面事件时所需要传递的消息中。
2、消息的接收者不知道发送者,甚至消息的发送者不需要预先知道消息的接收者。