来源: 伯乐在线 - 青玉伏案

链接:http://ios.jobbole.com/83229/

学习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 = ^(int a, int b)

{

//test ++; //报错

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

//blockVar++不报错;

blockVar ++;

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

int sum = a + b;

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

};

在声明的时候赋值

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

{

int sum = a + b;

return sum;

};

3.调用block

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

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

int sum = sumBlock(20, 30);

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

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

void blockFunction(int (^myBlock)(int, int))

{

int sum = myBlock(10,20);

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

}

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

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

代码如下:

__block int blockVar = 0;

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

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

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

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

测试代码如下:

void blockTest1()

{

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

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-10 13:30:25.710 Memory[1074:303] 两个字符串的初始值和初始地址

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

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

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

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

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

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

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

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

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

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

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

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

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

2014-08-10 13:30:25.715 Memory[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修饰观察其变化

{

__block NSString *hasBlock;

NSString *noBlock;

}

-(void)test;

@end

方法的实现:

@implementation BlockTest

-(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-10 16:32:42.497 Memory[1349:303] hasBlock = ludashi, hasBlock_p = 0x100006188

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

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

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

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

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

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

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

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

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

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

总结:

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

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

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

 
 
 

Objective-C中的Block(闭包) (轉載)的更多相关文章

  1. Objective-C中的Block(闭包)

    学习OC有接触到一个新词Block(个人感觉又是一个牛气冲天的词),但不是新的概念,不是新的东西.学过Javascript的小伙伴对闭包应该不陌生吧~学过PHP的应该也不陌生,在PHP5.3版本以后也 ...

  2. iOS开发之OC与swift开发混编教程,代理的相互调用,block的实现。OC调用Swift中的代理, OC调用Swift中的Block 闭包

    本文章将从两个方向分别介绍 OC 与 swift 混编 1. 第一个方向从 swift工程 中引入 oc类 1. 1 如何在swift的类中使用oc类    1.2  如何在swift中实现oc的代理 ...

  3. SQL2008中Merge的用法(轉載)

    在SQL2008中,新增了一个关键字:Merge,这个和Oracle的Merge的用法差不多,只是新增了一个delete方法而已.下面就是具体的使用说明: 首先是对merge的使用说明: merge ...

  4. Swift: 比较Swift中闭包传值、OC中的Block传值

    一.介绍 开发者对匿名函数应该很清楚,其实它就是一个没有名字的函数或者方法,给人直观的感觉就是只能看到参数和返回值.在iOS开发中中,它又有自己的称呼,在OC中叫Block代码块,在Swift中叫闭包 ...

  5. Objective-C中的Block回调模式

    在前面的博客中提到了Block的概念和使用方法,个人感觉Block最爽的用法莫过于在回调时用block.感觉比委托回调和目标方法回调用着要顺手,好不好用还得读者亲自用一下才知道.如果 读者之前用过SS ...

  6. ios 中的block应用

    在这个大冬天里默默敲着键盘,勿喷.今天学习swift过程中,学习到闭包,发现闭包和oc的block中有很多的相同之处,又重新学习了一下并且学习了一些高级点的用法,内容如下: 1.block格式说明:( ...

  7. Objective-C中的Block

    1.相关概念 在这篇笔记开始之前,我们需要对以下概念有所了解. 1.1 操作系统中的栈和堆 注:这里所说的堆和栈与数据结构中的堆和栈不是一回事. 我们先来看看一个由C/C++/OBJC编译的程序占用内 ...

  8. Swift 中的Closures(闭包)详解

    Swift 中的Closures(闭包)详解 在Swift没有发布之前,所有人使用OC语言编写Cocoa上的程序,而其中经常被人们讨论的其中之一 -- Block 一直备受大家的喜爱.在Swift中, ...

  9. 100% 加速 WebSAMS 3.0 (轉載)

    今日已經是WebSAMS Upgrade 的最後一日,已經有99.8% 學校成功upgrade WebSAMS 3.0.但有學校向我們反映WebSAMS 3.0 比2.0 慢,經過我們的Enginee ...

随机推荐

  1. j2se jndi

    http://blog.csdn.net/lldwolf/article/details/2299622 正如你可以看到,从JNDI中检索对象是相当方便,简单.通过使用JNDI来存储配置信息,无状态对 ...

  2. linux0.11文件分析

    在kernel包中有几个重要的文件夹和文件,他们各司其职,处理着有关内核的一些功能操作.其中文件夹有三个:blk_drv(块设备驱动),chr_drv(字符设备驱动),math(数学协处理器)  文件 ...

  3. 实用的eclipse adt 快捷键

    Ctrl + Shift + T: 打开类型:显示"打开类型"对话框来在编辑器中打开类型."打开类型"选择对话框显示工作空间中存在的所有类型如类.接口等.    ...

  4. 解决ImportError: cannot import name HTTPConnection的方法

    在写python程序的时候,使用from httplib import HTTPConnection,在run的时候提示ImportError: cannot import name HTTPConn ...

  5. Notepad++加上xml格式化的功能

    工作中需要用代码创建一个XML文件,创建完发现XML内容都处在同一行,导致非常不容易查看清楚XML代码.于是习惯性地用 Notepad++查看,想用它来对XML代码格式化一下. 于是找到了TextFX ...

  6. windows8安装xna4.0不能开发Xbox和PC端游戏的解决办法

    vs2012安装wp8后,只能开发手机端的xna游戏程序,没有xbox和pc端的,看来官方是不打算更新了,不过我们还是有办法的. 前提条件下,您得安装了vs2010和xna4.0 game studi ...

  7. UVa 1393 (容斥原理、GCD) Highways

    题意: 给出一个n行m列的点阵,求共有多少条非水平非竖直线至少经过其中两点. 分析: 首先说紫书上的思路,编程较简单且容易理解.由于对称性,所以只统计“\”这种线型的,最后乘2即是答案. 枚举斜线包围 ...

  8. NOI2005维修数列

    剧恶心的splay…… 为什么在bzoj上是超时,在自己的电脑上测的是栈溢出…… ; maxc=; var n,m,i,j,y,root,x,posi,t,head:longint; ch:char; ...

  9. [swustoj 917] K-lucky-number

    K-lucky-number(0917) 问题描述 K-lucky-number is defined as add up the number of each bit is a multiple o ...

  10. DOM的定义及DOM相关

    DOM : Document Object Model 文档对象模型文档:html页面文档对象:页面中元素文档对象模型:定义 为了能够让程序(js)去操作页面中的元素 DOM会把文档看作是一棵树,同时 ...