欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS(闭包)block传值详解

程序员文章站 2023-12-18 23:40:58
在iosapp开发的过程中 我们会用到很多需要传值的地方 传值的方式也多种多样 有:代理传值、通知传值、kvc、kvo、block、单例 等。其中block 因为其简洁实用...

在iosapp开发的过程中 我们会用到很多需要传值的地方 传值的方式也多种多样 有:代理传值、通知传值、kvc、kvo、block、单例 等。其中block 因为其简洁实用规范的代码 无疑是大牛们传值的不二选择 但对于初学者来说要理解并能运用 起初确实有些难以理解 以下我将细细的介绍下block

首先我总结了一下block的公式:

  1. 步骤1.block 的声明 返回值类型(^block 的名字)(参数列表);
  2. 步骤2.block 实现 block的名字 = ^(参数列表)(){};
  3. 步骤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修饰下 但具体机制还不太懂 希望高人指点,感谢大家对的支持。

上一篇:

下一篇: