代理、通知、KVO、KVC

代理

  • 代理 准确的说是一种软件设计模式
  • iOS当中一@protocol形式体现
  • 传递方式一对一

代理的工作流程

代理的工作流程

代理的循环引用

代理循环引用

问:为什么使用weak来解决循环引用,不是assign呢?

  • weak 表示对对象的弱引用,被weak修饰的对象随时可被系统销毁和回收。
  • 用weak修饰弱引用,不会使传入对象的引用计数加1。当一个对象被销毁时,指针被清空。
  • assigin 可以用非 OC 对象,而 weak 必须用于 OC 对象
  • 当指向的对象释放以后,weak会被自动设置为nil,而assign不会,所以会导致野指针的出现,可能会导致crash

协议中可以声明属性、方法

iOS Protocol中声明属性
iOS Protocol中声明属性的方法

  • @property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
  • @synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
  • @dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

通知

是通过观察者模式实现跨层传递消息的机制;
传递方式为1对多;

不同之处 代理 通知
设计模式 代理模式实现 观察者模式
传值方式 一对一传值 一对多传值
  • 通知是同步的还是异步的呢?

默认是同步的(所谓的同步就是发送通知之后 会阻塞当然线程,直到所有observer处理完成)

也可以让通知异步 ,具体参考//www.greatytc.com/p/d335cfdcc17d
1.将通知的发送放到子线程中
2.将通知的处理方法放到子线程中
3.通知的发送可以添加到NSNotificationQueue异步通知缓冲队列中,并指定为NSPostASAp或者NSPostWhenIdle类型发送(指定NSPostNow模式立即发送通知,得到的结果仍然是同步执行)

  • 如何实现通知的机制?
    通知是NS开头的。NS开头的框架无法知道源代码。
    如果要手动实现通知。如下图,我们需要一个map存储所有的通知,每个通知的名称notificationName关联一个列表Observer_list。列表里面的每个Observer存放在调用的方法、传递的参数等。
手动实现通知

KVO

KVO 是key-value observing的缩写。

什么是KVO?(面试)

KVO是对观察者设计模式的又一实现(KVO的实现机制)。
苹果使用了isa混写(isa-swizzling)来实现KVO。

KVO实现细节、原理?(面试)

1.当我们向A添加观察,系统会利用RuntimeAPI动态生成一个NSKVONotfiying_A类继承A;
2.并且让A的instance对象的isa指向这个全新的子类NSKVONotfiying_A;
3.NSKVONotfiying_A类重写观察字段的set方法(NSSetXXXValueAndNotify函数)。如图【重写set方法】,在set方法的前后添加上willChangeValueForKeydidChangeValueForKey方法。当观察的字段改变之后,set方法里面:
1)调用willChangeValueForKey:
2)调用原来的setter实现
3)didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法

KVO的实现原理
重写set方法

isa混写技术在KVO中怎么体现?(面试)

当我们向A添加观察,系统会生成一个NSKVONotfiying_A类继承A;将A的isa指针指向NSKVONotfiying_A,并重写观察字段的set方法。

哪几种赋值方式可以让KVO生效,为什么?(面试)

也就是说,观察类A的属性a,怎么对a进行赋值,可以调用到观察的回调方法。

  1. 通过KVC的方式进行赋值(setValue: forkey:);
  2. 通过.语法触发setter方法进行赋值;
  3. 成员变量直接赋值,并在赋值前后增加willChangeValueForKey、didChangeValueForKey方法。

我们通过下面进行实践:有MObject类,MObserver观察类。通过MObserver观察MObject中value的变化。

MObject类:

.h:
@interface MObject : NSObject
@property (nonatomic, assign) int value;
- (void)increase;
@end

.m:
@implementation MObject

- (id)init
{
    self = [super init];
    if (self) {
        _value = 0;
    }
    return self;
}

@end

MObserver类:进行观察,有新值变化就进行打印

#import "MObject.h"
@implementation MObserver

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    if ([object isKindOfClass:[MObject class]] &&
         [keyPath isEqualToString:@"value"]) {
        
        // 获取value的新值
        NSNumber *valueNum = [change valueForKey:NSKeyValueChangeNewKey];
        NSLog(@"value is %@", valueNum);
    }
}

ViewController中进行观察:
通过kvc和点语法触发setter方法,都可以成功收到观察的回调。

    MObject *obj = [[MObject alloc] init];
    MObserver *observer = [[MObserver alloc] init];
    
    //调用kvo方法监听obj的value属性的变化
    [obj addObserver:observer forKeyPath:@"value" options:NSKeyValueObservingOptionNew context:NULL];
   
    // 1. 通过kvc设置value:会调用value的setter方法,所以MObserver能成功收到value值变化的回调
    [obj setValue:@2 forKey:@"value"];

    //2.通过setter方法修改value;直接调用setter方法,可以收到观察的回调
    obj.value = 1;

    // 3. 通过成员变量直接赋值value能否生效?继续看下文。
    [obj increase];

如下,MObject中increase方法直接通过成员方法赋值,没有触发setter方法。MObserver不会收到回调方法。

- (void)increase
{
    //直接为成员变量赋值
    _value += 1;
}

成员变量前后添加上willChangeValueForKey、didChangeValueForKey方法后,MObserver就可以收到回调方法了。

- (void)increase
{
    //直接为成员变量赋值
    [self willChangeValueForKey:@"value"];
    _value += 1;
    [self didChangeValueForKey:@"value"];
}

KVC

  • 什么是KVC
    Key-value coding的缩写。是一种键值编码技术。
  • 通过键值编码技术,是否违背面向对象的编程思想,是否破坏面向对象的方法呢?
    会破坏。
    Key:是没有任何限制的,在知道某一个类内部私有名称的情况下,可以对私有变量进行访问的。破坏面向对象的思想

  • kvc的api

- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key; 
  • kvc使用
@interface MJCat : NSObject
@property (assign, nonatomic) int weight;
@end

@interface MJPerson : NSObject
@property (assign, nonatomic) int age;

@property (assign, nonatomic) MJCat *cat;
@end
        //为person的age赋值
        MJPerson *person = [[MJPerson alloc] init];
        [person setValue:@10 forKey:@"age"];
    
      //为person的cat对象里的weight赋值
       person.cat = [[MJCat alloc] init];
       [person setValue:@10 forKeyPath:@"cat.weight"];

KVC设值原理

KVC设值值的流程:


KVC设值原理

KVC设值值可以触发kvo,如下:其实系统默认在setValue:forkey(赋值的)前后调用了willchangValueForKey、didChangeValueForKey


kvc触发kvo本质写法

KVC取值原理

KVC取值原理
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容

  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,386评论 8 265
  • OC语言基础 1.类与对象 类方法 OC的类方法只有2种:静态方法和实例方法两种 在OC中,只要方法声明在@int...
    奇异果好补阅读 4,273评论 0 11
  • 代理 代理设计模式的作用:1.A对象监听B对象的一些行为,A成为B的代理2.B对象想告诉A对象一些事情,A成为B的...
    蔡少阅读 377评论 0 2
  • 面试题参考1 : 面试题[http://www.cocoachina.com/ios/20150803/12872...
    江河_ios阅读 1,737评论 0 4
  • 她就是她 颜色不一样的她 辛勤三十日,母瘦雏渐肥。 喃喃教言语,一一刷毛衣。 一旦羽翼成,引上庭树枝。 举翅不回顾...
    拾荒聽雨阅读 253评论 0 0