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。

时间: 2024-12-29 04:50:09

ios开发——实用技术篇&Block/KVO/通知/代理的相关文章

iOS开发——实用技术篇&amp;版本控制之Git的基本使用与总结

iOS开发——实用技术篇&版本控制之Git的基本使用与总结 updataing..............

iOS开发——实用技术篇&amp;版本控制之SVN的基本使用与总结

iOS开发——实用技术篇&版本控制之SVN的基本使用与总结 updataing..............

ios开发——实用技术篇&amp;Pist转模型详细介绍

Pist转模型详细介绍 关于Plist转模型在iOS开发中是非常常见的,每开一一个项目或者实现一个功能都要用到它,所以今天就给大家讲讲Plist怎么转成模型数据, 前提:必须有一个Plist文件或者通过一定的方式返回的plist数据 一:直接加载Plist数据 1 //定义一个数组属性 2 @property (nonatomic, assign) NSArray *apps; 获取Plist文件 1 //懒加载plist文件,返回一个apps数据,后面直接使用旧可以 2 -(NSArray *

ios开发——实用技术篇&amp;网络音频播放

网络音频播放 在日常的iOS开发中,我们通常会遇到媒体播放的问题,XCode中已经为我们提供了功能非常强大的AVFoundation框架和 MediaPlayer框架.其中AVFoundation框架中的AVAudioPlayer主要用于播放本地音频,也可以播放网络音频,但是需要先将 网络数据转化为data数据,用户体验较差,所有苹果公司提供了功能强大的AVPlayer用于播放网络音频(既流媒体),效果和可控性都比较好,现在就 重点介绍下AVPlayer中网络音频的播放: 下边是一个简单的实例:

ios开发——实用技术篇OC篇&amp;iOS的主要框架

iOS的主要框架         阅读目录 Foundation框架为所有的应用程序提供基本系统服务 UIKit框架提供创建基于触摸用户界面的类 Core Data框架管着理应用程序数据模型 Core Graphics框架帮助你创建图形 Core Animation允许你创建高级的动画和虚拟效果 OpenGL ES 框架提供2D和3D绘图工具 将别的框架添加到工程里 本文是<Sunvey the Major Framworks>一文的翻译 框架是一个目录,这个目录包含了共享库,访问共享库里代码

ios开发——实用技术篇&amp;开发总结余建议

iOS应用性能调优的25个建议和技巧 我要给出的建议将分为三个不同的等级: 入门级. 中级和进阶级: 入门级(这是些你一定会经常用在你app开发中的建议) 1. 用ARC管理内存 2. 在正确的地方使用reuseIdentifier 3. 尽可能使Views不透明 4. 避免庞大的XIB 5. 不要block主线程 6. 在Image Views中调整图片大小 7. 选择正确的Collection 8. 打开gzip压缩 中级(这些是你可能在一些相对复杂情况下可能用到的) 9. 重用和延迟加载V

ios开发——实用技术篇Swift篇&amp;播放MP3

播放MP3 1 // MARK: - 播放MP3 2 /*----- mp3 ------*/ 3 //定时器- 4 func updateTime() 5 { 6 //获取音频播放器播放的进度,单位秒 7 var cuTime:Float = Float(audioPlayer.currentTime) 8 9 //更新进度条 10 jinDuSlider.value = cuTime 11 12 //获取总时间 13 var duTime:Float = Float(audioPlayer.

ios开发——实用技术篇Swift篇&amp;加速计和陀螺仪

加速计和陀螺仪 1 //返回按钮事件 2 @IBAction func backButtonClick() 3 { 4 self.navigationController?.popViewControllerAnimated(true) 5 } 6 7 8 @IBOutlet var xLabel:UILabel! 9 @IBOutlet var yLabel:UILabel! 10 @IBOutlet var zLabel:UILabel! 11 12 @IBOutlet var orient

ios开发——实用技术篇OC篇&amp;获取设备唯一标识

获取设备唯一标识 WWDC 2013已经闭幕,IOS7 Beta随即发布,界面之难看无以言表...,简直就是山寨Android. 更让IOS程序猿悲催的是,设备唯一标识的MAC Address在IOS7中也失效了. IOS系统中,获取设备唯一标识的方法有很多: 一.UDID(Unique Device Identifier) UDID的全称是Unique Device Identifier,顾名思义,它就是苹果IOS设备的唯一识别码,它由40个字符的字母和数字组成. 二.UUID(Univers