03、3分钟教你搞定这该死的Delegate!代理与协议委托的深度理解
2015-12-17 17:56
501 查看
总结
做程序时,经常会碰到这样一种情况:在对象A中有一个对象B,在B中做某个操作时需要调用A对象的某个方法。这时,我们就需要用代理机制,也叫委托机制。还记得刚接触面向对象的时候,居然在B对象中又alloc了一个A对象,发现执行方法时没有works,那时不理解新alloc的对象和原来的对象A不是一个东东。
今天专门补习了一下哈,在网上找了一些资料,综合了一下,写了这篇菜鸟教程。
委托代理(delegate),顾名思义,把某个对象要做的事情委托给别的对象去做。那么别的对象就是这个对象的代理,代替它来打理要做的事。反映到程序中, 首先要明确一个对象的委托方是哪个对象,委托所做的内容是什么。委托机制在很多语言中都用到的,这只是个通用的思想,网上会有很多关于这方面的介绍。
首先,大家应该都明白的是委托是协议的一种,顾名思义,就是委托他人帮自己去做什么事。也就是当自己做什么事情不方便的时候,就可以建立一个委托,这样就可以委托他人帮自己去实现什么方法。
其次,我简单的总结了一下自己用到的委托的作用有两个,一个是传值,一个是传事件。
1.所谓传值经常用在b类要把自己的一个数据或者对象传给a类,让a类去展示或者处理。(切分紧耦合,和代码分块的时候经常用)
2.所谓传事件就是a类发生了什么事,把这件事告诉关注自己的人,也就是委托的对象,由委托的对象去考虑发生这个事件后应该做出什么反映。(这个经常见,例如在异步请求中,界面事件触发数据层改变等等)
3.利用委托赋值,这种方法感觉是为了不暴露自己的属性就可以给自己复值,而且这样更方便了类的管理,只有在你想要让别人给你赋值的时候才调用,这样的赋值更可控一些。(例如tableView中的委托(dateSource)中常见)。
最后,我想分享一下在使用委托的时候的一些心得和注意事项。
心得:delegate的命名要准确,尽量看名字就知道用法。delegate和通知有的用法有些象,但是前者是单对单的,后者是单对多的情况。
注意:在dealloc要把delegate至为nil,还有就是delegate设置属性的时候要用assign,不要用retain。
委托
在IOS中委托通过一种@protocol的方式实现,所以又称为协议.协议是多个类共享的一个方法列表,在协议中所列出的方法没有响应的实现,由其它人来实现.这叫好比我想买个手机,所以我有个buyIphone 方法,但是我不知道谁那买手机,所以把这个需求发布出去(比如公布在网站上),如果有卖手机的商人(也就是说他能实现buyIphone这个方法)看到,他就会接受我的委托,(在商人自己的类中实现),那么我的委托对象就指向了这个商人..当我要买手机的时候,直接找他就行了.例如:
.h文件中
@protocol MyDelegate -(void)buyIphone:(NSString *)iphoneType money:(NSString *)money; @end @interface My : NSObject { id<MyDelegate> deleage; } 或: @property(assign,nonatomic)id<MyDelegate> delegate; @end
代码中声明了一个协议名叫Mydelegate,在其中有一个buyIphone方法,即一个委托项。当我要购买手机的时候只需要通过delegate 调用 BuyIphone方法即可.
如下:
-(void)willbuy
{
[delegate buyIphone:@”iphone 4s” money:@”4888”];
}
我不必关心谁现实了这一委托,只要实现了这个委托的类,并且buyIphone是声明的委托中必须实现的方法,那么就一定能够得到结果.
例如:商人类实现了这一委托(用表示实现)
#import <Foundation/Foundation.h> #import "My.h" @interface Business : NSObject<MyDelegate> @end
然后在 @implementation Business 中调用 buyIphone方法
#import "Business.h" @implementation Business -(void)buyIphone:(NSString *)iphoneType money:(NSString *)money { NSLog(@"手机有货,这个价钱卖你了,发货中!!"); } @end
delegate是ios编程的一种设计模式。我们可以用这个设计模式来让单继承的objective-c类表现出它父类之外类的特征。再举个栗子��代理实现如下:
类GifView是继承自UIView的,它加载在RootViewController上来通过一个Timer播放动画。同时,RootViewController需要知道Timer的每次执行。代码如下。
首先,定义GifView,在其头文件中定义代理EveryFrameDelegate,同时声明方法- (void)DoSomethingEveryFrame;
#import <UIKit/UIKit.h> @protocol EveryFrameDelegate <NSObject> - (void)DoSomethingEveryFrame; @end @interface GifView : UIView { NSTimer *timer; id <EveryFrameDelegate> delegate; NSInteger currentIndex; } @property (nonatomic, retain) id <EveryFrameDelegate> delegate; @end
然后,只要在GifView.m中让Timer在每次执行的时候调用delegate来执行DoSomethingEveryFrame,代码如下:
- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { timer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(play) userInfo:nil repeats:YES]; [timer fire]; } return self; } -(void)play { [delegate DoSomethingEveryFrame]; }
GifView上的工作就完成了。
下面是RootViewController中的代码,RootViewController只要在定义GifView的时候指定其代理为自身,就可以知道Timer的每次执行:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. CGRect rect = CGRectMake(0, 0, 200, 200); GifView *tmp = [[GifView alloc] initWithFrame:rect]; tmp.delegate = self; [self.view addSubview:tmp]; [tmp release]; } - (void)DoSomethingEveryFrame { NSLog(@"I'm the delegate! I'm doing printing!"); }
GifView中Timer每次执行都会打印一行
I’m the delegate! I’m doing printing!
故,RootViewController就知道Timer的每次执行了。
再一个举栗��:利用textFieldDelegate代理方法改变屏幕颜色
TestDelegateView.h
// Created by 康大亮 on 15/11/18. // Copyright © 2015年 com.evergrande. All rights reserved. #import <UIKit/UIKit.h> @protocol TestDelegateViewDelagate <NSObject> //定义一个可选的代理方法 @optional - (void) passMySelf:(id)testDelegateView exchangeColor:(NSString *)exchangeColor;// @required @end @interface TestDelegateView : UIView @property (nonatomic, assign)id<TestDelegateViewDelagate> delegate;//使用assign不需管理内存,不用规避循环引用 @end
TestDelegateView.m
#import "TestDelegateView.h" @implementation TestDelegateView - (instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { [self addBtn]; } return self; } - (void)addBtn{ UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; [btn setFrame:CGRectMake(200, 200, 100, 100)]; [btn setTitle:@"调用代理方法" forState:UIControlStateNormal]; //添加回调方法 [btn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:btn]; } - (void)btnAction:exchangeColor{ //调用协议方法 [self.delegate passMySelf:self exchangeColor:@"改变背景颜色"]; } @end
AppDelegate.m
#import "AppDelegate.h" #import "TestDelegateView.h"//导入 @interface AppDelegate ()<UITextFieldDelegate, TestDelegateViewDelagate>//协议代理(多个用逗号隔开) @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; [self.window setRootViewController:[[UIViewController alloc] init]]; //自定义 UITextField *field = [[UITextField alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; field.placeholder = @"测试键回收"; field.delegate = self; //指定代理 [self.window addSubview:field]; //使用系统的 TestDelegateView *testView = [[TestDelegateView alloc] initWithFrame:self.window.frame]; testView.delegate = self;//指定代理 testView.backgroundColor = [UIColor yellowColor]; [self.window addSubview:testView]; return YES; } #pragma mark -- textFieldDelegate代理方法 // 点击键盘Return键时候的回调方法 - (BOOL)textFieldShouldReturn:(UITextField *)textField{ // 取消第一响应者,编辑状态停止,用户交互停止,键盘会回收。称为第一响应者的方法是??? [textField resignFirstResponder];// NSLog(@"---%s", __func__); return YES; } // - (void)passMySelf:(id)testDelegateView exchangeColor:(NSString *)exchangeColor { [testDelegateView setBackgroundColor:[UIColor greenColor]]; NSLog(@"%@", exchangeColor); NSLog(@"---%s", __func__); } @end
点击键盘Return键时候的回调方法
- (BOOL)textFieldShouldReturn:(UITextField *)textField{ // 取消第一响应者,编辑状态停止,用户交互停止,键盘会回收。称为第一响应者的方法是??? [textField resignFirstResponder];// NSLog(@"---%s", __func__); return YES; }
相关文章推荐
- JavaScript 文章备注
- linux 免用户密码登录
- 学习CRYPTO第二天
- View hierarchy-视图层次
- 工作环境搭建(8) - CentOS7命令行安装Android SDK
- jQuery学习笔记(一)
- 安装成功的nginx如何添加未编译安装模块
- ggplo2学习笔记——基本图形类型
- 10-动画组
- C3P0数据库连接池相关配置
- win7桌面ie删不掉
- Objective-c语言_NSData(不可变数据)和NSMutableData(可变数据)
- Python中的Numpy、SciPy、MatPlotLib安装与配置
- oc 学习习题答案
- java 动态编译 方法内联
- CryptoAPI例子-最全1
- Nginx系列教程:ngx_cache_purge模块
- C 语言循环之break、continue
- Java Annotation
- 第十一周项目二----用二叉树求解代数表达式