Object-c 中的block就好像一段C函数般,由函数名,有返回值,有参数,由函数体等

1.简单的block

 ^(int A ,int B)
{
int C=A*B;
return C;
};

上述代码表示block有两个整形参数A和B.在block体中进行A和B的相乘,将结果作为block的返回值返回出去。

2.将block作为参数的API

在程序开发时,当需要一个NSArray对象的所有元素进行遍历时,除了for循环,开发者可以使用block进行遍历,代码如下:

  NSArray *arrChar=[@"A/B/C/D/E/F" componentsSeparatedByString:@"/"];
//遍历元素
[arrChar enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"\nindex:[%d], value:[%@]",idx,obj);
if(idx == )
{
*stop=YES;
}
}];

这段代码运行后,在控制台上留下了如下日志:

index:[0], value:[A]
index:[1], value:[B];
index:[2], value:[C];
index:[3], value:[D];
index:[4], value:[E];

这里,NSArray对象所使用的API主要是一个对自己元素的遍历功能,enumerateObjectsUsingBlock方法的参数需要是一个block对象,在NSArray的帮助文档中,我们找到了enumerateObjectsUsingBlock的声明,内容如下:

-(void)enumerateObjectsUsingBlock:(void)(^(id obj,NSInterger idx,BOOL *stop))block

所传入的3个参数中,前两个是表明当前元素指针和序号的输入参数,开发者直接拿来使用即可。最后一个参数讲一个布尔类型的指针传递进来,显然是属于一个典型的输入参数。这个参数让开发者可以灵活的控制遍历的继续执行是否。

3.block的声明

block在声明时,需要遵循如下所示的格式结构。

<返回值类型> + (^<block名字>) + (<参数类型1>, <参数类型2>...)

根据enumerateObjectsUsingBlock的结构,我们声明的block变量对象如下:

void (^arrayEnumerateBlock)(id,NSUInteger,BOOL *);

对于声明完的block变量,可以直接进行初始化,也可以进行赋值。block的初始化格式如下:

void (^arrayEnumerateBlock)(id,NSUInteger,BOOL *)=^(id anObject, NSUInteger index, BOOL *isStop)
{
NSLog(@"\nindex:[%d], value:[%@]", index, anObject); //序号4, 则停止遍历
if(index == )
{
*isStop=YES;
}
};

上述代码中对于变量的初始化,开发者同样需要加上“^”符号表明这是一个block类型。不过block的返回值和block名不用写明,block名作为声明的一部分已经在声明时写明,至于返回值,只需要在block体中严格遵守返回类型即可。

4.block 的 typedef

在平时开发中,我们习惯于使用typedef定义属于自己框架的东西,本质上其实是为了类型使用更加统一。

而block由于有着相对复杂的声明方式,不如可以考虑将block的格式进行typedef,之后所有需要遵循这个block格式的对象声明再也不需要考虑格式的撰写,并且由于block有着函数指针般的接口协议特征,使用typedef定义过的block格式,当作为接口提供外部调用时,调用者可以明确具体需要给与的参数格式。

同样是enumerateObjectsUsingBlock所用的那个block格式,typedef定义示例如下

typedef void (^ArrayEnumerateBlockType)(id ,NSUInteger, BOOL *);

虽然typedef后接着的格式和前一小节中block声明格式相当相似,不过typedef所书写的内容是类型名字,而block声明时所书写的是变量对象的名字。所以在这里,我们特意以ArrayEnumerateBlockType定义类型名和之前的arrayEnumerateBlock变量类型名加以区分。

一旦有了typedef过得block类型后,到哪里都能够简单的使用这个block了,初始化代码如下:

ArrayEnumerateBlockType aEnumerateBlock=^(id aObject, NSUInteger index, BOOL *isStop)
{
//跟前面一样
}

5.block体的外部变量使用的奇怪之处

首先,让我们来看看以下代码。

     NSUInteger result   = ;
NSUInteger changeValue=;
//block变量声明
NSUInteger (^testReturnValueBlock)(NSUInteger, NSUInteger) = ^(NSUInteger param1, NSUInteger param2)
{
return param1+param2+changeValue;
}; result=testReturnValueBlock(,);
NSLog(@"1.[%d]",result); changeValue++;
result=testReturnValueBlock(,);
NSLog(@"2.[%d]",result);

执行结果却是

1.[3]
2.[3]

是不是觉得相当奇怪,我明明在第一次日志打印后对changeValue变量执行了++操作,其实打印的结果并没有错,我们需要更深入的了解block内部机制才能够看懂这其中的奥妙。

在block体中,我们不仅能够访问到block声明的传入参数,也能够正常访问到block以外的变量,不过,对于block以外的变量来说,如果把它放在block内进行访问也罢赋值也罢,一旦进入了block体中,基本类型变量会被block进行一次copy后以一个临时变量存放在block体中,而指针变量会被block进行一次retain后也以一个临时变量存放起来,无论是基本数据类型还是指针,被block使用了,就表明他的生命周期除了自己本身所在的作用域,又多了一个block体的作用域,也就是说:

(1)基本数据类型在block中的地址已经发生变化,所以block体外对于此数据类型的值修改对于体内的值毫无影响。

(2)block所copy或者retain的变量,一旦block结束,也就一起跟着被释放和销毁了。

(3)所谓的block会进行retain的指针类型,也包含Object-c中的所有对象。

6.克服外部变量的魔咒

(1)可以把外部变量修改成  static NSUInteger changeVaue=0;

static 关键字意味着changeValue的地址不再被我们放置于栈中,不过也并不在堆中,而是放在全局数据区,拥有一个永远不会改变的地址。

(2)也可以在外部变量前加上 __block   如:  __block NSUInteger changeValue=0;

当一个变量被__block所修饰时,block体中就会知道,即使使用到这个外部变量,也坚决不会去进行retain或者copy,这样就能够保证内外统一了

Object-c Block的使用及说明的更多相关文章

  1. iOS通知中心升级 -可设置按优先级执行block

    简单介绍下,这是需求驱动中发现iOS的NotificationCenter有很多功能无法实现,于是对其进行了一层包装.相当于手动管理观察者栈和监听者期望执行的事件,因此可以为其添加了很多新增的功能,将 ...

  2. block的语法

    主要内容: 1. 开始使用block(Getting Started with Blocks) 2. block概念综述(Conceptual Overview) 3. 声明和创建block(Decl ...

  3. Core Java Volume I — 4.6. Object Construction

    4.6. Object ConstructionYou have seen how to write simple constructors that define the initial state ...

  4. ios专题 -block用法

    what is block Blocks are a language-level feature added to C, Objective-C and C++, which allow you t ...

  5. (译文)IOS block编程指南 3 概念总览

    Conceptual Overview(概览) Block objects provide a way for you to create an ad hoc function body as an ...

  6. 简洁的KVO -- 使用Block响应事件

    涉及内容: KVO,Runtime,Category,Block 首先创建NSObject的Category 举个例子是这样的: 随后定义你需要响应的Block结构 我简单一点就这样咯 typedef ...

  7. 【原】iOS学习之PINCache第三方缓存框架

    在项目中总是需要缓存一些网络请求数据以减轻服务器压力,业内也有许多优秀的开源的解决方案.通常的缓存方案都是由内存缓存和磁盘缓存组成的,内存缓存速度快容量小,磁盘缓存容量大速度慢可持久化. 1.PINC ...

  8. Functional Programming without Lambda - Part 2 Lifting, Functor, Monad

    Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...

  9. 相克军_Oracle体系_随堂笔记005-Database buffer cache

    本章主要阐述SGA中的Database buffer cache. Buffer cache { 1.pin (读写瞬间的状态) 2.clean 3.dirty 4.unused } --Databa ...

  10. IOS开发基础知识--碎片28

    1:通用的weakify和strongify /** * 强弱引用转换,用于解决代码块(block)与强引用self之间的循环引用问题 * 调用方式: `@weakify_self`实现弱引用转换,` ...

随机推荐

  1. Mahout源码MeanShiftCanopyDriver分析之二MeanShiftCanopyMapper仿造

    首先更正一点,昨天处理数据的时候是有问题的,直接从网页中拷贝的文件的空格是有问题的,直接拷贝然后新建的文件中的空格可能有一个两个.三个的,所以要把两个或者三个的都换为一个,在InputMapper中下 ...

  2. cocos2d-x -- 渠道SDK【棱镜】接入(2)

    上一章<cocos2d-x -- 渠道SDK[棱镜]接入(1)>,已经接入好了SDK.如今要准备加入渠道了,以豌豆荚为例. 详细流程: 1.加入渠道:

  3. Java DecimalFormat 格式化数字

    我们经常要将数字进行格式化,比如取2位小数,这是最常见的.Java 提供 DecimalFormat 类,帮你用最快的速度将数字格式化为你需要的样子.下面是一个例子: importjava.text. ...

  4. debug jdk

    1.解压jdk安装路径中的src.zip如:c:\src. 注意一般只选择编译java javax org 三个文件夹就足够了,剩余的文件夹删除掉 2.列出要编译的源文件:dir /B /S /X c ...

  5. 常用Json

    一般Json是页面与页面之间传递使用. Json用途        1 后台与前台数据交互,并且数据较复杂,如果数据单一,直接传递字符串,然后在前台用js分割就行. 2 webservice和html ...

  6. [LeetCode]题解(python):137-Single Number II

    题目来源: https://leetcode.com/problems/single-number-ii/ 题意分析: 给定一个数组,数组里面每一个数字都出现了3次除了一个,找出那个数.要求时间复杂度 ...

  7. MYSQL 执行计划

    Explain语法 EXPLAIN SELECT …… 变体: 1. EXPLAIN EXTENDED SELECT …… 将执行计划“反编译”成SELECT语句,运行SHOW WARNINGS 可得 ...

  8. 转: when.js原理和核心实现

    这篇文章可以看作是屈屈同学关于when.js的文章<异步编程:When.js快速上手>的续篇. 屈屈的文章中详细介绍了when.js,在这里关于when.js的使用我就不多复述了,大家可以 ...

  9. 在PADS LAYOUT中如何隐藏不需要的鼠线?

    如下图示,将net GPR_0的鼠线隐藏. 鼠标右键,选择网络----选择你要隐藏的网络------右键选择view nets----点击对话框右边View List里你所选的网络-----在右下角t ...

  10. Win7下使用protel99se、protel99

    很多网友需要用的protel99se,由于该软件开发的时间比较就早,在现在笔记本普及,尤其是win7普及的情况下,用该软件着实让许多人头痛,有人选择安装XP系统,但这就牺牲了win7良好的操作体验.也 ...