ios开发——实用技术篇&Block/KVO/通知/代理


Block/KVO/通知/代理简单介绍与使用

关于iOS开发中数据传递的方法有很多种,但是使用最多的就是这里的四种,而且我们要学会在适当的时候使用合适的方式,才能充分的提高app的性能

下面简单介绍一下这些方法的使用

Block

第一、综述

  block是OC中另外一种对象和对象的通信方式,是一对一的关系,类似于delegate,而通知时一对多的关系

第二、定义block类型

  int (^myBlock)(int)

第三、block的声明

  mylock=^(int a)

  {

  int result =a*a;

  return result;

  }

第四、block的调用

  block(20);

  code sample如下所示:

  int(^myBlock)(int); myBlock=^(int a){ NSLog(@"%d",a); return 0; }; myBlock(20);


第五、另外一种声明方法

  typedef int(^MyBlock)(int);

  MyBlock myblock=^(int a)

  {

  NSLog(@"%d",a);

  return 30;

  };

  myblock(30);

第六、block作为参数传递

  - (void)viewDidLoad

  {

  [super viewDidLoad];

  // Do any additional setup after loading the view, typically from a nib.

  //define block defination

  NSLog(@"before");

  MyBlock myblock=^(int a)

  {

  NSLog(@"%d",a);

  return 30;

  };

  [self testBlock:myblock];

  }

  -(void)testBlock:(MyBlock)myblock

  {

  myblock(10);

  }

第七、block和变量

  局部变量:

  在block中,会把局部变量当成常量变量

  int num=10;

  int num=30;

  MyBlock myblock=^(int a)

  {

  num=20; //此处会报错

  NSLog(@"%d",a);

  return 30;

  };

 1 什么是Block:从C的声明符到Objective-C的Blocks语法
 2 块代码以闭包得形式将各种内容进行传递,可以是代码,可以是数组无所不能。块代码十分方便将不同地方的代码集中统一,使其易读性增强。
 3 
 4 来看这里怎么进行数组传递。
 5 
 6 typedef void (^Arr_Block)(NSArray *array);
 7 
 8 - (void)showArrayUsingBlock:(Arr_Block)block
 9 {
10     NSDictionary *dict = @{@"array": @[@"Chelsea", @"MUFC", @"Real Madrid"]};
11     NSArray *array = dict[@"array"];
12     block(array);
13 }
14 
15 调用方法,显示
16 
17 - (IBAction)blockCallBack
18 {
19     [self showArrayUsingBlock:^(NSArray *array) {
20         _outputLabel.text = array[1];
21     }];
22 }
23 
24 三种模式都很轻松~

 

KVO

Kvo是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数 据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。(这样的机制听起来类 似Notification,但是notification是需要一个发送notification的对象,一般是 notificationCenter,来通知观察者。而kvo是直接通知到观察对象。)

适用kvo时,通常遵循如下流程:

1 注册:

-(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context

keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)。
options是监听的选项,也就是说明监听泛黄的额字典包含什么值。有两个常用的选项:

NSKeyValueObservingOptionsNew 指返回的字典包含新值。
NSKeyValueObservingOptionsOld 值返回的字典包含旧值。

2 实现变化方法:

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void*)context

change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。

 1  1 .person类 
 2 @implementation Person 
 3 @synthesize name,age;//属性name 将被监视 
 4 -(void) changeName 
 5 { 
 6     name=@"changeName directly"; 
 7 } 
 8 @end 
 9  
10  
11 2.PersonMonitor类  监视了name属性 
12 @implementation PersonMonitor 
13  
14 - (void)observeValueForKeyPath:(NSString *)keyPath 
15                       ofObject:(id)object 
16                         change:(NSDictionary *)change 
17                        context:(void *)context 
18 { 
19     if ([keyPath isEqual:@"name"]) 
20     { 
21         NSLog(@"change happen, old:%@   new:%@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]); 
22     } 
23 } 
24 @end 
25  
26  
27 3测试代码 
28  
29    //初始化被监视对象 
30     Person *p =[[Person alloc] init]; 
31    //监视对象 
32    PersonMonitor *pm= [[PersonMonitor alloc]init]; 
33     [p addObserver:pm forKeyPath:@"name" options:(NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld) context:nil]; 
34    
35 //测试前的数据 
36     NSLog(@"p.name is %@",p.name); 
37     
38 //通过setvalue 的方法,PersonMonitor的监视将被调用 
39   [p setValue:@"name kvc" forKey:@"name"]; 
40   
41 //查看设置后的值 
42    NSLog(@"p name get by kvc is %@",[p valueForKey:@"name"]); 
43  
44 //效果和通过setValue 是一致的     
45 p.name=@"name change by .name="; 
46  
47  //通过person自己的函数来更改name  
48      [p changeName];  
49  
50  结果是 
51 输出 
52 2011-07-03 16:35:57.406 Cocoa[13970:903] p.name is name 
53 2011-07-03 16:35:57.418 Cocoa[13970:903] change happen, old:name   new:name kvc 
54 2011-07-03 16:35:57.420 Cocoa[13970:903] p name get by kvc is name kvc 
55 2011-07-03 16:35:57.421 Cocoa[13970:903] change happen, old:name kvc   new:name change by .name= 

 


通知:


通知需要有一个通知中心:NSNotificationCenter,自定义通知的话需要给一个名字,然后监听。

优点:通知的发送者和接受者都不需要知道对方。可以指定接收通知的具体方法。通知名可以是任何字符串。

缺点:较键值观察(KVO)需要多点代码,在删掉前必须移除监听者。

 1 通知中心的方式可以不用设置代理,但是需要设置观察者和移除观察者。
 2 
 3 
 4 
 5 代码
 6 
 7 - (IBAction)callBack
 8 {
 9     NSDictionary *dict = @{@"array": @[@"Chelsea", @"MUFC", @"Real Madrid"]};
10     NSArray *array = dict[@"array"];
11     [[NSNotificationCenter defaultCenter] postNotificationName:@"OutputArrayNotification" object:array];
12 }
13 
14 注册和移出观察者
15 
16 - (void)viewWillAppear:(BOOL)animated
17 {
18     [super viewWillAppear:animated];
19     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(outputWithNote:) name:@"OutputArrayNotification" object:nil];
20 }
21 
22 - (void)viewDidDisappear:(BOOL)animated
23 {
24     [super viewDidDisappear:animated];
25     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"OutputArrayNotification" object:nil];
26 }
27 
28 显示
29 
30 - (void)outputWithNote:(NSNotification *)aNotification
31 {
32     NSArray *receiveArray = [aNotification object];
33     _outputLabel.text = receiveArray[0];
34 }

 


代理:

通过setDelegate来设置代理对象,最典型的例子是常用的TableView.

优点:支持它的类有详尽和具体信息。

缺点:该类必须支持委托。某一时间只能有一个委托连接到某一对象。

 

 1 作为IOS中最常见的通讯模式,代理几乎无处不在。
 2 
 3 
 4 
 5 看实例
 6 这里有一个数组,我们首先通过代理的方式将数组传递到其他方法中去。
 7 设置协议及方法
 8 
 9 @protocol CallBackDelegate;
10 
11 @interface ViewController : UIViewController
12 @property (weak, nonatomic) id<CallBackDelegate> delegate;
13 @end
14 
15 @protocol CallBackDelegate <NSObject>
16 - (void)showArrayWithDelegate:(NSArray *)array;
17 @end
18 
19 @interface ViewController () <CallBackDelegate>
20 
21 点击按钮传递数组让其显示
22 
23 - (IBAction)delegateCallBack
24 {
25     NSDictionary *dict = @{@"array": @[@"Chelsea", @"MUFC", @"Real Madrid"]};
26     NSArray *array = dict[@"array"];
27     [self.delegate showArrayWithDelegate:array];
28 }
29 
30 调用,显示
31 
32 - (void)showArrayWithDelegate:(NSArray *)array
33 {
34     _outputLabel.text = array[2];
35 }
36 
37 最重要也是最容易忽略的,就是一定要设置delegate的指向。
38 完成后屏幕显示

 

 

总结:

从上面的分析中可以看出3中设计模式都有各自的优点和缺点。其实任何一种事物都是这样,问题是如何在正确的时间正确的环境下选择正确的事物。下面就讲讲如何发挥他们各自的优势,在哪种情况下使用哪种模式。注意使用任何一种模式都没有对和错,只有更适合或者不适合。 每一种模式都给对象提供一种方法来通知一个事件给其他对象,而且前者不需要知道侦听者。在这三种模式中,我认为KVO有最清晰的使用案例,而且针对某个需 求有清晰的实用性。而另外两种模式有比较相似的用处,并且经常用来给controller间进行通信。那么我们在什么情况使用其中之一呢?

根据我开发iOS应用的经历,我发现有些过分的使用通知模式。我个人不是很喜欢使用通知中心。我发现用通知中心很难把握应用的执行流程。 UserInfo dictionaries的keys到处传递导致失去了同步,而且在公共空间需要定义太多的常量。对于一个工作于现有的项目的开发者来说,如果过分的使用 通知中心,那么很难理解应用的流程。

我觉得使用命名规则好的协议和协议方法定义对于清晰的理解controllers间的通信是很容易的。努力的定义这些协议方法将增强代码的可读性,以及更好的跟踪你的app。代理协议发生改变以及实现都可通过编译器检查出来,如果没有将会在开发的过程中至少会出现crash,而不仅仅是让一些事情异常工作。甚至在同一事件通知多控制器的场景中,只要你的应用在controller层次有着良好的结构,消息将在该层次上传递。该层次能够向后传递直至让所有需要知道事件的controllers都知道。

当然会有delegation模式不适合的例外情况出现,而且notification可能更加有效。例如:应用中所有的controller需要知道一个事件。然而这些类型的场景很少出现。另外一个例子是当你建立了一个架构而且需要通知该事件给正在运行中应用。

根据经验,如果是属性层的时间,不管是在不需要编程的对象还是在紧紧绑定一个view对象的model对象,我只使用观察。对于其他的事件,我都会使用delegate模式。如果因为某种原因我不能使用delegate,首先我将估计我的app架构是否出现了严重的错误。如果没有错误,然后才使用notification。

 

 
文章来自:http://www.cnblogs.com/iCocos/p/4550169.html
© 2021 jiaocheng.bubufx.com  联系我们
ICP备案:鲁ICP备09046678号-3