iOS(闭包)block传值详解
在iosapp开发的过程中 我们会用到很多需要传值的地方 传值的方式也多种多样 有:代理传值、通知传值、kvc、kvo、block、单例 等。其中block 因为其简洁实用规范的代码 无疑是大牛们传值的不二选择 但对于初学者来说要理解并能运用 起初确实有些难以理解 以下我将细细的介绍下block
首先我总结了一下block的公式:
- 步骤1.block 的声明 返回值类型(^block 的名字)(参数列表);
- 步骤2.block 实现 block的名字 = ^(参数列表)(){};
- 步骤3.block 的调用 block的名字();
下面是一个简单的block
// 声明 void(^blockname)(int num,nsstring *string); // 实现 blockname = ^(int num,nsstring *string) { nslog(@"%d,%@",num,string); }; // 调用 blockname(520,@"phyone_"); }
由该例可以看出block的代码执行顺序和其他的代码执行顺序不一样 它是先执行声明代码 然后执行调用代码 最后才执行实现代码 由此我们利用block的回调性质 达到我们传值效果 当然这只是在一个页面的一段代码 只是说明了它具有传值的作用 下面我们来试试 多页面之间的block反向传值 由于是反向传值 所以我们创建两个viewcontroller (viewcontroller,next_viewcontroller)先由viewcontroller跳到next_viewcontroller里将里面的值反向传给viewcontroller
以下是代码
viewcontroller.m里面
- (void)viewdidload { [super viewdidload]; self.view.backgroundcolor = [uicolor purplecolor]; uilabel *lable = [[uilabel alloc]initwithframe:cgrectmake(100, 200, 200, 100)]; lable.backgroundcolor = [uicolor browncolor]; [self.view addsubview:lable]; uitapgesturerecognizer *tap = [[uitapgesturerecognizer alloc]initwithtarget:self action:@selector(tap)]; [self.view addgesturerecognizer:tap]; } - (void)tap { next_viewcontroller *nvc = [[next_viewcontroller alloc]init]; nvc.block = ^(nsstring *content){ nslog(@"%@",content); uibutton *button = [[uibutton alloc]initwithframe:cgrectmake(100, 200, 100, 100)]; [button settitle:content forstate:uicontrolstatenormal]; button.backgroundcolor = [uicolor orangecolor]; [self.view addsubview:button]; }; [self presentviewcontroller:nvc animated:yes completion:nil]; }
next_viewcontroller.h里面
//block 是分配在栈里面的用copy @property(nonatomic,copy) void(^block)(nsstring *content);
next_viewcontroller.m里面
<p style="margin-top: 0px; margin-bottom: 0px; font-family: menlo;"><span style="font-size:12px;">{</span></p> <p style="margin-top: 0px; margin-bottom: 0px; font-family: menlo;"><span style="font-size:12px;"> void(^imagenameblock_1)(nsstring *imagename);</span></p> <p style="margin-top: 0px; margin-bottom: 0px; font-family: menlo;"><span style="font-size:12px;"> void(^lableblock)(nsstring *tontenttext);</span></p> <p style="margin-top: 0px; margin-bottom: 0px; font-family: menlo;"><span style="font-size:12px;">}</span></p>
- (void)viewdidload { [super viewdidload]; self.view.backgroundcolor = [uicolor orangecolor]; uibutton *button = [uibutton buttonwithtype:uibuttontypecustom]; button.frame = cgrectmake(100, 200, 100, 50); [button settitle:@"123456" forstate:uicontrolstatenormal]; button.backgroundcolor = [uicolor redcolor]; [button addtarget:self action:@selector(buttonaction:) forcontrolevents:uicontroleventtouchupinside]; [self.view addsubview:button]; } - (void)buttonaction:(uibutton *)sender { // 点击按钮 返回上一个页面 同时通过block 把这个值传到上一个页面 self.block(sender.titlelabel.text); [self dismissviewcontrolleranimated:nil completion:nil]; }
另外:block 还有两个问题
1.怎么改变block里面的值
用上面的代码 在viewcontroller.m viewdidload 里面 添加代码
1.局部变量 定义一个图片名字的block */ // 局部变量 void(^imagenameblock)(nsstring *imagename); // 如果想修改block里面的值 需添加__block修饰 // __block uiimage *image; imagenameblock = ^(nsstring *imagename) { image = [uiimage imagenamed:imagename]; self.view.backgroundcolor = [uicolor colorwithpatternimage:image]; }; imagenameblock(@"17.jpg");
就会出现 use of undeclared identifier 'image' 错误情况 原因是我们试图改变block里面的值 解决办法就是 添加 __block 修饰(解注释
__block uiimage *image;) 就行了
2.block的循环引用
用上面的代码 在viewcontroller.m viewdidload 里面 添加代码
// 全局变量 // block循环 引用 解决 我们用弱引用 __block __weak viewcontroller *vc = self; __block uiimage *image = nil; imagenameblock_1 = ^(nsstring *imagename) { image = [uiimage imagenamed:imagename]; vc.view.backgroundcolor = [uicolor colorwithpatternimage:image]; }; uilabel *lable = [[uilabel alloc]initwithframe:cgrectmake(100, 200, 200, 100)]; lable.backgroundcolor = [uicolor browncolor]; [self.view addsubview:lable]; uitapgesturerecognizer *tap = [[uitapgesturerecognizer alloc]initwithtarget:self action:@selector(tap)]; [self.view addgesturerecognizer:tap];
再添加两个方法
- (void)loaddata { imagenameblock_1(@"17.jpg"); } - (void)viewwillappear:(bool)animated { [self loaddata]; }
当出现循环引用是我们用__weak修饰下 但具体机制还不太懂 希望高人指点,感谢大家对的支持。