代理Delegate传值
- Xcode新建Single View Application项目
Main.storyboard拖拽UILabel,Button和UINavigationBar控件,添加好自动布局约束,如下图:
新建File –> Cocoa Touch Class –> DelegateByValViewController,勾选”Also create XIB file”,如下图:
DelegateByValViewController.xib 拖拽UITextField,UIButton和UINavigationBar控件,添加约束,并拖线UITextField输出接口和UIButton按钮点击事件,如下图:
DelegateByValViewController.h文件里需要设置代理协议和代理属性:
#import <UIKit/UIKit.h> // 代理协议 begin @protocol DelegateByValViewControllerDelegate <NSObject> - (void)changeText:(NSString *)text; @end // 代理协议 end @interface DelegateByValViewController : UIViewController // 代理属性 @property (nonatomic, assign) id <DelegateByValViewControllerDelegate> delegate; @end
DelegateByValViewController.m文件里需要取得UITextField 的值,并在回退按钮事件中让代理去执行更改文本:
- (IBAction)onBackPressed:(id)sender { // 代理执行更改文本 [self.delegate changeText:self.inputedText.text]; // 返回 [self dismissViewControllerAnimated:YES completion:^{ }]; }
Main.storyboard布局上的显示值的UILabel拖线到ViewController,定义输出接口,代理传值按钮拖线实现点击事件:
- (IBAction)gotoDelegateByValPage:(id)sender { DelegateByValViewController *detalsViewCtrl = [[DelegateByValViewController alloc] init]; // 设置代理 detalsViewCtrl.delegate = self; //页面跳转 [self presentViewController:detalsViewCtrl animated:YES completion:^{ }]; }
最后在ViewController.m文件中遵守DelegateByValViewControllerDelegate协和并执行协议中的方法:
- (void)changeText:(NSString *)text { self.shownText.text = text; }
总结:代理模式到此结束,相对来说比较复杂的一种传值方式。上面只贴出了关键代码,具体代码见DEMO。
通知传值
在上面的项目中新建File –> Cocoa Touch Class –> NotificationByValViewController,勾选”Also create XIB file”,如下图:
NotificationByValViewController.xib 拖拽UITextField,UIButton和UINavigationBar控件,添加约束,并拖线UITextField输出接口和UIButton按钮点击事件,如下图:
NotificationByValViewController.m中的按钮返回事件中发送名称为“LabelTextChangeNotification”的通知
- (IBAction)backBtnOnClick:(id)sender { // 发送通知 [[NSNotificationCenter defaultCenter] postNotificationName:@"LabelTextChangeNotification" object:nil userInfo:@{@"inputedText": self.labelText.text}]; // 返回 [self dismissViewControllerAnimated:YES completion:^{ }]; }
Main.storyboard中的通知传值按钮拖线到ViewController.m并实现点击事件:
- (IBAction)gotoNotificationByValPage:(id)sender { NotificationByValViewController *notificationByValCtrl = [[NotificationByValViewController alloc] init]; [self presentViewController:notificationByValCtrl animated:YES completion:^{ }]; }
ViewController.m中的viewDidLoad方法需要去注册通知“LabelTextChangeNotification”,并实现收到通知的方法:
- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeTextByNotification:) name:@"LabelTextChangeNotification" object:nil]; } - (void)changeTextByNotification:(NSNotification *)notification { // 取得值 NSString *text = [[notification userInfo] objectForKey:@"inputedText"]; // 显示 self.shownText.text = text; }
总结:通知传值方式比代理传值更简单。别忘了在dealloc方法中取消注册removeObserver。
块Block传值
按照上述新建文件的方法,新建BlockByValViewController
在BlockByValViewController.h文件中,定义一个参数为字符串的block:
typedef void (^testBlock) (NSString *text); @interface BlockByValViewController : UIViewController @property (nonatomic, copy) testBlock block; @end
BlockByValViewController.m的返回方法中:
- (IBAction)onBackOnClick:(id)sender { self.block(self.inputedText.text); [self dismissViewControllerAnimated:YES completion:nil]; }
ViewController.m文件中,块传值按钮的点击事件代码:
- (IBAction)gotoBlockbyValPage:(id)sender { BlockByValViewController *blockCtrl = [[BlockByValViewController alloc] init]; [self presentViewController:blockCtrl animated:YES completion:nil]; blockCtrl.block = ^(NSString *str) { self.shownText.text = str; }; }
总结:iOS4.0以后支持的block,封装的代码可以在任何时候执行,这种方式传值也比较简单,多线程中常用的传值方式。
最后附上DEMO工程:DEMO下载