Blocks是C语言的扩充功能。用一句话来表示Blocks的扩充功能:带有自动变量(局部变量)的匿名函数

  block其实是一个代码块,但是它的神奇之处在于在内联(inline)执行的时候(这和C++很像)还可以传递参数。同时block本身也可以被作为参数在方法和函数间传递,这就给予了block无限的可能。

  Block一般有如下几种使用情况:

1、作为一个本地变量(local variable)

  returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};

2、作为@property

  @property (nonatomic, copy) returnType (^blockName)(parameterTypes); 

3、作为方法的参数(method parameter)

  - (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;

4、作为方法参数的时候被调用

  [someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];

5、使用typedef来定义block,可以事半功倍

  typedef returnType (^TypeName)(parameterTypes);
  TypeName blockName = ^returnType(parameters) {...};

  Block与C语言的函数指针是类似的

//C的函数
//格式:返回值 方法名 (参数...)
//1.返回值是void 没有参数的C函数
void cfun (void){
//调用时才执行函数里面的内容
printf("this is a c method\n");
}
//2.返回值是void 带两个参数的C函数
void cfun1(int a,int b){
printf("%d\n",a+b);
}
//3.有返回值 带两个参数的C函数
int cfun2(int c,int d){
int muli = c*d;
return muli;
} -(void)testC{
cfun();
cfun1(, );
int muli = cfun2(, );
NSLog(@"乘积是%d",muli); //1.声明一个返回值是void,不带参数的函数指针
//格式:返回值(*xxx)(参数...)
void (*fun1)(void);
fun1 = &cfun; //函数名本身就是一个地址,&可加可不加
fun1();
//2.声明一个返回值是void,带两个参数的函数指针
void (*fun2)(int a,int b);
fun2 = cfun1;
fun2(,);
//3.声明一个返回值是int,带两个参数的函数指针
int (*fun3)(int a,int b);
fun3 = cfun2;
NSLog(@"%d",fun3(,));
}

  下面我们来看怎么定义Block

  1.无参数无返回值的Block

/**
* void :就是无返回值
* emptyBlock:就是该 bloc k的名字
* ():这里相当于放参数。由于这里是无参数,所以就什么都不写
*/
void (^emptyBlock)() = ^(){
NSLog(@"无参数,无返回值的Block");
};
emptyBlock();

  2.有参数无返回值的Block

/**
* 调用这个block进行两个参数相加
*
* @param int 参数A
* @param int 参数B
*
* @return 无返回值
*/
void (^sumBlock)(int ,int ) = ^(int a,int b){
NSLog(@"%d + %d = %d",a,b,a+b);
};
/**
* 调用这个sumBlock的Block,得到的结果是20
*/
sumBlock(,);

  3.有参数有返回值的Block

  /**
* 有参数有返回值
*
* @param NSString 字符串1
* @param NSString 字符串2
*
* @return 返回拼接好的字符串3
*/
NSString* (^logBlock)(NSString *,NSString *) = ^(NSString * str1,NSString *str2){
return [NSString stringWithFormat:@"%@%@",str1,str2];
};
//调用logBlock,输出的是 我是Block
NSLog(@"%@", logBlock(@"我是",@"Block"));

  那么block与函数指针有什么区别呢

  首先:函数指针是对一个函数地址的引用,这个函数在编译的时候就已经确定了。而block是一个函数对象,是在程序运行过程中产生的。在一个作用域中生成的block对象分配在栈(stack)上,和其他所有分配在栈上的对象一样,离开这个作用域,就不存在了。Block允许开发者在两个对象之间将任意的语句当做数据进行传递,往往这要比引用定义在别处的函数直观。

  其次:blocks是inline的,并且它对局部变量是只读的。

  修改 block 之外的变量

  默认情况下,在程序块中访问的外部变量是复制过去的,即写操作不对原变量生效。比如下面的语句:

- (void)viewDidLoad
{
//将Block定义在方法内部
int x = ;
void (^sumXAndYBlock)(int) = ^(int y){
x = x+y;
printf("new x value is %d",x);
};
sumXAndYBlock();
}

  这段代码有什么问题呢,Xcode会提示x变量错误信息:Variable is not assigning (missing __block type),这时候给int x = 100;语句前面加上__block关键字即可,如下:

  __block int x = ;//这样在Block的{}体内,就可以修改外部变量了。

  Block循环引用

  刚刚说过,block在iOS开发中被视作是对象,因此其生命周期会一直等到持有者的生命周期结束了才会结束。另一方面,由于block捕获变量的机制,使得持有block的对象也可能被block持有,从而形成循环引用,导致两者都不能被释放:

@interface ViewController (){
void (^_cycleReferenceBlock)(void);
} @end @implementation ViewController - (void)viewDidLoad {
   [super viewDidLoad];
    _cycleReferenceBlock = ^{
      NSLog(@"%@", self);
      //引发循环引用
     };
  }

  遇到这种代码编译器只会告诉你存在警告,很多时候我们都是忽略警告的,这最后会导致内存泄露,两者都无法释放。跟普通变量存在__block关键字一样的,系统提供给我们__weak的关键字用来修饰对象变量,声明这是一个弱引用的对象,从而解决了循环引用的问题:

  __weak typeof(*&self) weakSelf = self;
  _cycleReferenceBlock = ^{
   NSLog(@"%@", weakSelf); //弱指针引用,不会造成循环引用
  };

  Block作为property属性实现页面之间传值

  这里举例一个Block回调修改上一下界面的背景颜色。控制器1跳转到控制器2,然后在控制器2触发事件回调修改控制器1的背景颜色为红色。

  VC2的实现

#import <UIKit/UIKit.h>
/**
* 定义了一个changeColor的Block。这个changeColor必须带一个参数,这个参数的类型必须为id类型的
* 无返回值
* @param id
*/
typedef void(^changeColor)(id);
@interface ViewController2 : UIViewController 

/**
* 用上面定义的changeColor声明一个Block,声明的这个Block必须遵守声明的要求。
*/
@property (nonatomic, copy) changeColor backgroundColor; @end
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//声明一个颜色
UIColor *color = [UIColor redColor];
//用刚刚声明的那个Block去回调修改上一界面的背景色
self.backgroundColor(color);
}

  VC1的实现

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
ViewController2 *vc =[[ViewController2 alloc]init];
// 回调修改颜色
vc.backgroundColor = ^(UIColor *color){
self.view.backgroundColor = color;
};
[self.navigationController pushViewController:vc animated:YES];
}

查看demo

Block小结的更多相关文章

  1. 块对象block小结(2)

    MRC环境下 ////  main.m//  blcok////  Created by ios on 16/4/6.//  Copyright © 2016年 ios. All rights res ...

  2. 块对象block小结

    blcok的形式 ^(参数列){主体} block作为返回值

  3. inode与block知识总结

    inode概述:硬盘要分区,然后格式化,创建文件系统在每个Linux存储设备的分区被格式化为ext3文件系统后一般有两个部分:    第一部分Inode:存储这些数据的属性信息(大小,属主,归属的用户 ...

  4. linux 基础 文件系统 用户权限

    描述Linux系统的启动过程? 1.开机自检 BIOS 2.MBR引导 3.GRUB菜单 4.加载内核 5.运行init进程 6.从/etc/inittab读取运行级别 7.根据/etc/rc.sys ...

  5. linux运维、架构之路-linux文件属性

    1.查看文件属性 ls -lhi 文件属性详细说明 1. 第一列: inode索引节点编号 2. 第二列:文件类型及权限 3. 第三列:硬链接数 4. 第四列:文件或目录所属的用户,即文件的所有者 5 ...

  6. Linux运维学习笔记-文件系统知识体系总结

    文件系统知识总结 新买的硬盘要存放数据需要怎么做? 首先将硬盘装机做RAID,做完RAID后进行分区,分完区后格式化创建文件系统,最后存放数据. 硬盘的内外部结构: 物理形状: 接口类型: IDE(I ...

  7. 第一阶段·Linux运维基础 第3章·文件属性、正则表达式、文件权限

    01-文件属性内容介绍 02- inodeyublock讲解 03-访问oldboyfile的寻宝过程 04-inode与block小结 05-磁盘空间不足案例详解 06-Linux文件类型及拓展名 ...

  8. 26.centos7基础学习与积累-012-文件和目录的属性

    从头开始积累centos7系统运用 大牛博客:https://blog.51cto.com/yangrong/p5 1.文件的属性(文件的信息描述): [root@python01 ~]# ls -l ...

  9. JavaScript设计模式(一):单例模式

    单例模式的定义与特点 单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式.例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗 ...

随机推荐

  1. 学习WindowsPhone 2013/12/22

    菜鸟一枚,只能边看别人的博客变学习来提升自己,参考博客内容:http://blog.csdn.net/column/details/wp-comming.html?page=3 ,稍微看了一下,写的还 ...

  2. 在uboot上创建菜单

    一.原理 菜单其实就是一个uboot中的命令,和其他的命令没有什么差别.  uboot启动时,如果进入uboot命令模式,先运行这个命令,就会打印出一个菜单界面. 在uboot的命令模式,通过键入“m ...

  3. Nine Great Books about Information Visualization

    Nine Great Books about Information Visualization Maybe it’s anachronistic to celebrate static, print ...

  4. Tomcat8 配置Oracle11g数据源

    1:context.xml <Resource name="jdbcoracle" auth="Container" type="javax.s ...

  5. Spring中用@Component、@Repository、@Service和 @Controller等标注的默认Bean名称会是小写开头的非限定类名

    今天用调度平台去调用bean中的方法时,提示找不到bean.经查,发现是由于如果在标注上没有提供name属性值,则默认的bean名称是小写开头的,而不是大写开头的. 下面是其他文档参阅: 使用过滤器自 ...

  6. Delphi中的THashTable

    在Delphi中,Inifiles单元中有一个TStringHash的类,不过它的Value仅支持Integer(其实也不是问题,有其它类型可以将变量变为Pointer),有点不舒服,今天没事做就把它 ...

  7. Spring的OpenEntityManagerInViewFilter

    在Java Web项目中使用Hibernate经常会遇到LazyInitializationException .这是因为controller和model层(java代码)将通过JPA的一些启用了延迟 ...

  8. 矩阵(快速幂):COGS 963. [NOI2012] 随机数生成器

    963. [NOI2012] 随机数生成器 ★★   输入文件:randoma.in   输出文件:randoma.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] 栋 ...

  9. Vim笔记

    复制多行: v 可视化,选择多行,然后yy复制.

  10. [基础] C++与JAVA的内存管理

    在内存管理上(总之一句话——以后C++工程,一定要用智能指针!) 1.同是new一个对象,C++一定得手动delete掉,而且得时刻记住能delete的最早时间(避免使用空指针).JAVA可以存活于作 ...