iOS开发-block详解

来源:互联网 发布:大清亡了 知乎 编辑:程序博客网 时间:2024/05/04 12:17

学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西。学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也支持闭包, 也就是OC中所提到的Block。 到底什么是闭包或者block呢?用大白话说就是匿名函数,也就是在函数中可以包含这函数。就是在函数中可以定义匿名函数然后在函数中调用。学习OC中的block之前也小担心一下,Block在OC中属于高级的部分,心里有又有个疑问:学起来难不难?看过Block的部分,感觉Block挺好理解的,用起来也挺顺手的,Block没我想象中的那么难理解。


废话少说,学习一门新的编程语言是少不了代码量的支持的,所以代码是少不了的。下面就通代码来认识一下OC中的block的使用。


Block基础部分


1.Block的声明


Block的定义和函数的声明差不多,就是把函数名改成(^blockName)即可。下面是block声明的代码。


有返回值的


int(^sumBlock)(int,int);


无返回值的


void(^myBlock)(int,int);


2.给block块赋值


给声明好的block,赋值。block的值就是个函数体,给block块赋值有两种方式,一个在声明的时候赋值,一个是先声明在赋值。


先声明再赋值


//代码块的声明

void(^myBlock)(int,int);

//给代码块赋值

myBlock = ^(inta,int b)

{

//test ++; //报错

NSLog(@"main_test = %d",test);

//blockVar++不报错;

blockVar ++;

NSLog(@"blockVar = %d",blockVar);

intsum = a + b;

NSLog(@"a + b = %d",sum);

};


在声明的时候赋值


int(^sumBlock)(int,int) = ^(inta,int b)

{

intsum = a + b;

returnsum;

};


3.调用block


block的使用和普通函数的使用相同,调用方法如下:


//调用代码块并接收返回值

intsum = sumBlock(20,30);


4.把block当做参数传入函数


//把代码块作为函数参数

voidblockFunction(int(^myBlock)(int,int))

{

intsum = myBlock(10,20);

NSLog(@"fun_sum = %d",sum);

}


5.在代码块中使用局部变量和全局变量


在block中可以和对全局变量进行访问和修改,但对局部变量只可以访问,若想修改的话,我们可以在声明局部变量的时候加上关键字__block


代码如下:


__blockintblockVar =0;


Block进阶 参考博客:http://www.cnblogs.com/NarutoYq/


下面的这些内容是参考上面的博客进一步学习的Block的内容,代码是参考这上面的博客自己写的,也就是说下面的东西算是伪原创吧。小伙伴们如果没大看懂下面的东西,请去上面的博客中进一部的了解一下block.


1.局部变量可变对象和不可变对象在block中的引用


下面会提供一部代码,这部分代码的功能是定义两个局部变量,一个是可变对象,一个是不可变对象,然后再定义一个Block, 在block中引用两个局部变量。上面提到了在代码块中可以引用局部变量但是不可以更改其值,除非在声明的时候加上__block关键字。


测试代码如下:


voidblockTest1()

{

//定义两个变量一个是可变的一个是不可变的

NSString*str1 = @"str1";

NSMutableString*str2 = [NSMutableString stringWithFormat:@"str2"];

//初始值

NSLog(@"两个字符串的初始值和初始地址");

NSLog(@"str1 = %@, str1_p = %p",str1,str1);

NSLog(@"str2 = %@, str2_p = %p",str2,str2);

//定义block在block中输出连个变量的值和参数

void(^myBlock)() = ^()

{

NSLog(@"******************************************");

NSLog(@"在block块中输出局部变量的可变和不可变变量");

NSLog(@"str1 = %@, str1_p = %p",str1,str1);

NSLog(@"str2 = %@, str2_p = %p",str2,str2);

};

//修改前赋值

str1 = @"str1_update";

[str2 appendString:@"_update"];

NSLog(@"******************************************");

NSLog(@"输出修改后的值和地址");

NSLog(@"str1 = %@, str1_p = %p",str1,str1);

NSLog(@"str2 = %@, str2_p = %p",str2,str2);

//调用block

myBlock();

NSLog(@"******************************************");

NSLog(@"调用block后的值和地址");

NSLog(@"str1 = %@, str1_p = %p",str1,str1);

NSLog(@"str2 = %@, str2_p = %p",str2,str2);

}


代码说明:给定义的各一个可变和不可变的对象一个初始值,然后在调用代码块的时候修改两个局部变量的值,然后再代码块中显示变量的值。


运行结果如下:


2014-08-1013:30:25.710Memory[1074:303]两个字符串的初始值和初始地址

2014-08-1013:30:25.711Memory[1074:303] str1 = str1,str1_p = 0x100005ef0

2014-08-1013:30:25.712Memory[1074:303] str2 = str2,str2_p = 0x100204330

2014-08-1013:30:25.712Memory[1074:303] ******************************************

2014-08-1013:30:25.712Memory[1074:303]输出修改后的值和地址

2014-08-1013:30:25.713Memory[1074:303] str1 = str1_update,str1_p = 0x100005fd0

2014-08-1013:30:25.713Memory[1074:303] str2 = str2_update,str2_p = 0x100204330

2014-08-1013:30:25.713Memory[1074:303] ******************************************

2014-08-1013:30:25.714Memory[1074:303]block块中输出局部变量的可变和不可变变量

2014-08-1013:30:25.714Memory[1074:303] str1 = str1,str1_p = 0x100005ef0

2014-08-1013:30:25.714Memory[1074:303] str2 = str2_update,str2_p = 0x100204330

2014-08-1013:30:25.714Memory[1074:303] ******************************************

2014-08-1013:30:25.715Memory[1074:303]调用block后的值和地址

2014-08-1013:30:25.715Memory[1074:303] str1 = str1_update,str1_p = 0x100005fd0

2014-08-1013:30:25.715Memory[1074:303] str2 = str2_update,str2_p = 0x100204330


从上面的输出结果我们可以看到,在代码块中输出的不可变对象是原有的值,而不是我们改后的值,地址也是初始的地址。而对于可变对象,值是我们修改后的值,而地址使用原有的地址。如果要想block和不可变局部变量绑定的话,我们要加上_block


还是引用上面博客中的一段话来做一下总结吧:


对值类型的修改,如果block初始化后,无法同步到block内部

对于引用类型的修改,如果block初始化后,修改指针指向,即指向另外一块内存,这样也是无法同步到block内部

对于引用类型的修改,如果block初始化后,对指针指向的内存进行修改,即NSMutableArray add 、remove操作,这样是可以用同步到block内部,但block内部同样无法修改。


2.成员变量在block中的使用


成员变量在block中的使用是加上self->a使用的,所以在声明成员变量的时候加不加__block,在成员函数中的代码块中都可以访问修改;


代码走起:


interface:

@interface BlockTest : NSObject

//声明两个成员变量一个用__block 和 不用__block修饰观察其变化

{

__blockNSString*hasBlock;

NSString*noBlock;

}

-(void)test;

@end


方法的实现:


@implementationBlockTest

-(void)test

{

//分别给两个成员变量赋初始值

hasBlock = @"ludashi";

noBlock = @"ludashi";

NSLog(@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p",hasBlock,hasBlock);

NSLog(@" noBlock = %@, noBlock_p = %p",noBlock,noBlock);

//定义block

void(^myBlock)() = ^()

{

//修改加__block的成员变量的值

hasBlock = @"ludashi_update";

NSLog(@"block中输出的内容");

NSLog(@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p",hasBlock,hasBlock);

NSLog(@" noBlock = %@, noBlock_p = %p",noBlock,noBlock);

};

//改变noBlock的值

noBlock = @"ludashi_update";

NSLog(@"更新后的值");

NSLog(@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p",hasBlock,hasBlock);

NSLog(@" noBlock = %@, noBlock_p = %p",noBlock,noBlock);

//调用block

myBlock();

//调用block后的值

NSLog(@"调用myBlock后的值");

NSLog(@"hasBlock = %<a href='http://www.jobbole.com/members/uz441800'>@,</a> hasBlock_p = %p",hasBlock,hasBlock);

NSLog(@" noBlock = %@, noBlock_p = %p",noBlock,noBlock);

}

@end


输出结果:


2014-08-1016:32:42.497Memory[1349:303] hasBlock =ludashi,hasBlock_p = 0x100006188

2014-08-1016:32:42.499Memory[1349:303]noBlock = ludashi,noBlock_p = 0x100006188

2014-08-1016:32:42.499Memory[1349:303]更新后的值

2014-08-1016:32:42.500Memory[1349:303] hasBlock = ludashi,hasBlock_p = 0x100006188

2014-08-1016:32:42.500Memory[1349:303]noBlock = ludashi_update,noBlock_p = 0x100006828

2014-08-1016:32:42.500Memory[1349:303] block中输出的内容

2014-08-1016:32:42.501Memory[1349:303] hasBlock = ludashi_update,hasBlock_p = 0x100006828

2014-08-1016:32:42.501Memory[1349:303]noBlock = ludashi_update,noBlock_p = 0x100006828

2014-08-1016:32:42.501Memory[1349:303]调用myBlock后的值

2014-08-1016:32:42.502Memory[1349:303] hasBlock = ludashi_update,hasBlock_p = 0x100006828

2014-08-1016:32:42.502Memory[1349:303]noBlock = ludashi_update,noBlock_p = 0x100006828


总结:


  • 对于一个、多个成员变量,不管是否用__block修饰(用不用都没任何影响),block结构体会生成一个成员 :self,并且会引用成员变量所属的对象实例 self。

  • 对于成员变量的修改都是通过对象self指针引用来实现的。

  • block内部对于成员变量的访问也是通过block结构体对象的成员self 指针引用来实现的。

0 0
原创粉丝点击