iOS中通知、代理、Block、KVO

在一个复杂的,有状态的系统中,当一个对象的状态发生改变,如何通知系统,并对状态改变做出相应的行为是必需考虑的一个问题,在iOS中为这类问题提供了4种解决方法:

1、NSNotifiactaionNSNotificationCenter:通知中心
2、Delegate:代理
3、Block:回调(Callback)
4、KVO(Key-Value Observing):键值观察

一、NSNotification 和 NSNotificationCenter

每个运行中的application都有一个NSNotificationCenter的成员变量,它的功能就类似公共栏。对象注册关注某个确定的notification,我们把这些注册对象叫做 observer。其它的一些对象会给center发送notifications,center将该notifications转发给所有注册对该notification感兴趣的对象,我们把这些发送notification的对象叫做 poster。
1、在要发出通知消息的地方:

[[NSNotificationCenter defaultCenter] postNotificationName:@"Notification_isHaveBanner" object:nil userInfo:@{@"ishavebanner":@"1"}];

2、在要接收通知消息的地方:

//对象注册,并关连消息
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reciveBannernNotice:) name:@"Notification_isHaveBanner" object:nil];
#pragma mark 接收通知处理传递消息
-(void) reciveBannernNotice:(NSNotification *)notification
{
    NSString *bannerStr = [notification.userInfo objectForKey:@"ishavebanner"];
    if ([bannerStr isEqualToString:@"0"]) {
        isHaveBanner = NO;
    }else if([bannerStr isEqualToString:@"1"])
    {
        isHaveBanner = YES;
    }else{
        isHaveBanner = NO;
    }
}

一、Delegate(代理)

delegate(代理)是iOS编程的一种设计模式,简单来说就是一个委托方的类让另外一个代理方的类具体实现其定义的方法。怎样写一个代理设计模式

1、你要明确你的协议名称,一般来讲名称都是:控件类名 + Delegate
2、代理方法中一般都是声明为@optional(程序默认情况下是@required)
3、代理方法名一般以控件开头
4、代理方法至少有一个参数

举例:来个保姆和婴儿之间是怎样利用代理协议来实现一个简单的找过过程,婴儿类要坐的事委托保姆类做。
1、首先,我们创建一个婴儿类,继承自NSObject ,接下来在Baby.h文件中创建下面的代码

#import <Foundation/Foundation.h>

// 定义一份代理协议
@protocol BabyDelegate <NSObject>
- (void)babyWantEat:(Baby *)baby;
- (void)babyWantSleep:(Baby *)baby;
@end

@interface Baby : NSObject

/** 吃了多少东西 */
@property (nonatomic, assign) int food;
/** 睡意 */
@property (nonatomic, assign) int sleep;

/** 饿了 */
- (void)wantEat;
/** 困了 */
- (void)wantSleep;

/** 代理对象 */
@property (nonatomic, weak) id<BabyDelegate> delegate;
@end

2、接下来是Baby.m文件中创建下面的文件

#import "Baby.h"

@implementation Baby
- (void)wantEat
{
    NSLog(@"婴儿想吃东西");

    // 通知保姆喂婴儿
    if ([self.deleate respondsToSelector:@selector(babyWantEat:)]){
        [self.delegate babyWantEat:self];
    }
}

- (void)wantSleep
{
    NSLog(@"婴儿想睡觉");

    // 通知保姆哄婴儿睡觉
    if ([self.deleate respondsToSelector:@selector(babyWantSleep:)]){
    [self.delegate babyWantSleep:self];
    }
}

@end

3、下面创建一个保姆类同样继承自NSObject,下面是Nurse.h文件中的代码

#import "Baby.h"
#import <Foundation/Foundation.h>
@interface Nurse : NSObject <BabyDelegate>
@end

4、接下来是Nurse.m文件中保姆需要在代理委托方法中做她的工作

#import "Nurse.h"
@implementation Nurse
- (void)babyWantEat:(Baby *)baby
{
    //baby是代理委托方传过来的值
    baby.food += 20;
    NSLog(@"Nurse喂婴儿吃东西--现在的食量是%d", baby.food);
}

- (void)babyWantSleep:(Baby *)baby
{
    baby.sleep += 20;

    NSLog(@"Nurse哄婴儿睡觉--现在的睡意是%d", baby.sleep);
}
@end

三、Block(回调)

直接举例:一个Block回调修改上一界面的背景颜色。

ViewController1 控制器1,ViewController2 控制器2。控制器1跳转到控制器2,然后在控制器2触发事件回调修改控制器1的背景颜色为红色。

1、ViewController2实现:

#import <UIKit/UIKit.h>
@interface ViewController2 : UIViewController
/**
 *  定义了一个changeColor的Block。这个changeColor必须带一个参数,这个参数的类型必须为id类型的
 *  无返回值
 *  @param id
 */
typedef void(^changeColor)(id);
/**
 *  用上面定义的changeColor声明一个Block,声明的这个Block必须遵守声明的要求。
 */
@property (nonatomic, copy) changeColor backgroundColor;
@end


-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //声明一个颜色
    UIColor *color = [UIColor redColor];
    //用刚刚声明的那个Block去回调修改上一界面的背景色
    self.backgroundColor(color);
}

1、ViewController1实现:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    ViewController2 *vc =[[ViewController2 alloc]init];
    // 回调修改颜色
    vc.backgroundColor = ^(UIColor *color){
        self.view.backgroundColor = color;
    };
    [self.navigationController pushViewController:vc animated:YES];
}

四、KVO(Key-Value Observing)

KVO是Object-C中定义的一个通知机制,其定义了一种对象间监控对方状态的改变,并做出反应的机制。对象可以为自己的属性注册观察者,当 这个属性的值发生了改变,系统会对这些注册的观察者做出通知。其用途十分广泛,比方说,你的下载进度条是根据下载百分比决定的,那么,可以通过观察下载百 分比的改变,刷新进度条的样式,来直观的反应下载进度等等。

A.注册观察者:

//第一个参数observer:观察者 (这里观察self.myKVO对象的属性变化)
//第二个参数keyPath: 被观察的属性名称(这里观察self.myKVO中num属性值的改变)
//第三个参数options: 观察属性的新值、旧值等的一些配置(枚举值,可以根据需要设置,例如这里可以使用两项)
//第四个参数context: 上下文,可以为kvo的回调方法传值(例如设定为一个放置数据的字典)
[self.myKVO addObserver:self forKeyPath:@"num" options:
NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
注意:这里的self.myKVO是被观察的对象,可以是self本身、也可以是定义的self.tableview等等。forKeyPath对应的一定要是这个对象的属性名称。

B. 属性(keyPath)的值发生变化时,收到通知,调用以下方法:

//keyPath:属性名称
//object:被观察的对象
//change:变化前后的值都存储在change字典中
//context:注册观察者时,context传过来的值
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
   //do something...
}

其他相关链接:开发该选择Blocks还是Delegates

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

推荐阅读更多精彩内容