原文参考博文:

http://blog.devtang.com/2013/07/28/a-look-inside-blocks/

http://www.cnblogs.com/kesalin/archive/2013/04/30/ios_block.html

block 实际上可以理解成是Objective-C 语言对于闭包的实现。配合上 dispatch_queue,可以方便地实现简单的多线程编程和异步编程。

关于闭包,可以理解成是一个函数(或指向函数的指针),再加上该函数执行的外部的上下文变量。

这里介绍关于block的:

1,内部实现,数据结构介绍

2,block 的三种类型及其相关的内存管理方式

3,block 如何通过 capture 变量来达到访问函数外的变量

一个 block 实际是一个对象,它主要由一个 isa 和 一个 impl 和 一个 descriptor 组成。更具体的说来,结构如下:

对应的结构体定义如下,

struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};

可以看出,主要包含6部分,

1,isa指针,所有对象都有这个指针。指向对象的类结构。

2,invoke指针,函数指针,指向具体的block实现的函数调用地址

3,variables,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

4,reserved,保留字段。5,flags,descriptions,一些附加描述信息,比如size等。

OC中,一共三种类型的block,

1,_NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。

2,_NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。

3,_NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

block对外部变量的引用:

主要包含2类,

1,对于 block 外的变量引用,block 默认是将其复制到其数据结构中来实现访问的。

2,对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的。

=======

block使用时的几个注意点:

1,block中的变量拷贝,是在实现时,对引用到的它所在方法中定义的栈变量进行一次只读拷贝。

这个变量是只读的,比如

id result = nil;

[context performBlockAndWait:^{

result = block();

}];

会报错,variable is not assignable。

需要对其有写操作时,可以加__block。

2,非内联(inline)block 不能直接访问 self。

  这种情况,可以将self 当作参数传递到 block 中才能使用。而且这个时候self的属性,只能通过setter 或 getter方法访问,不能用点语法。

typedef NSString* (^IntToStringInlineConverter)(NSInteger paramInteger);

// 非内联block

IntToStringConverter independentBlockObject = ^(id self, NSInteger paramInteger) {
    KSLog(@" >> self %@, memberVariable %d", self, [self memberVariable]);
NSString *result = [NSString stringWithFormat:@"%d", paramInteger];
KSLog(@" >> independentBlockObject %@", result);
return result;
};

// 内联block,用到self则不需要传self,也可以用点语法。
- (void)testAccessSelf
{
// Independent
[self convertIntToString:20 usingBlockObject:independentBlockObject]; // Inline
IntToStringInlineConverter inlineBlockObject = ^(NSInteger paramInteger) {
KSLog(@" >> self %@, memberVariable %d", self, self.memberVariable);
NSString *result = [NSString stringWithFormat:@"%d", paramInteger];
KSLog(@" >> inlineBlockObject %@", result);
return result;
};
[self convertIntToStringInline:20 usingBlockObject:inlineBlockObject];
}

3,使用 weak–strong避免循环引用

  内联block直接使用self时,需要小心,避免循环引用。

  block的本质其实还是一个对象。当self强持有这个block,而这个block又强持有self时,就会导致循环引用。

  换句话也就是说,只有释放了self才可以释放被self强持有的block。但self又被block强持有,无法释放。

  

  __weak KSViewController * wself = self;
_observer = [[NSNotificationCenter defaultCenter]
addObserverForName:@"TestNotificationKey"
object:nil queue:nil usingBlock:^(NSNotification *n) {
KSViewController * sself = wself;
if (sself) {
NSLog(@"%@", sself);
}
else {
NSLog(@"<self> dealloc before we could run this code.");
}
}];

  weak-strong的作用是,

  外部传入一个self的弱引用。这样block对象并没有强持有self,当self被释放的时候,wself 变成 nil。这样已经可以解决循环引用的问题。

  但是为了在block运行过程中不至于出现wself被释放,所以一般会声明一个__strong的变量,持有wself。这样,在self被释放后,block可以本正常释放,sself也就被释放。

【引】objective-c,3:关于block的更多相关文章

  1. Objective-C( block的使用)

    block block用来保存一段代码 block的标志:^ block跟函数很像:可以保存代码.有返回值.有形参.调用方式跟调用方法一样 block内部可以访问外面的变量 默认情况下,block内部 ...

  2. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  3. Swift正在使用NSURLConnection异步下载同步(实例解析)

    原版的blog.转载请注明出处 http://blog.csdn.net/hello_hwc 一.同步异步两个概念 简单来讲.同步就是函数或者闭包(objective c中的block)运行完成才干返 ...

  4. 完整详细的说明GCD列(一)dispatch_async;dispatch_sync;dispatch_async_f;dispatch_sync_f

    为什么要写这个系列,由于百度了一下.我们正在寻找一个非常比较片面的Blog.抄来抄去,写作是很粗糙. 所以,我想写这个系列,尝试记录官方网站GCD强大的全功能的表达.为了方便他们,也方便他人,假设有发 ...

  5. Objective C block背后的黑魔法

    前言 block在Objective C开发中应用非常广泛,我们知道block会捕获外部对象,也知道使用block要防止循环引用. "知其然而不知其所以然"是一件非常痛苦的事情,那 ...

  6. 初学Objective - C语法之代码块(block)

    一.block声明 1.无参数,无返回值: void (^sayHi)(); 2.有参数,有返回值: NSInteger (^operateOfValue)(NSInteger num); block ...

  7. Objective C中的ARC的修饰符的使用---- 学习笔记九

    #import <Foundation/Foundation.h> @interface Test : NSObject /** * 默认的就是__strong,这里只是做示范,实际使用时 ...

  8. Objective的字符串拼接 似乎没有Swift方便,但也可以制做一些较为方便的写法

    NSString *str1 = @"字符串1"; NSString *str2 = @"字符串2"; //在同样条件下,Objective的字符串拼接 往往只 ...

  9. Objective C ARC 使用及原理

    手把手教你ARC ,里面介绍了ARC的一些特性, 还有将非ARC工程转换成ARC工程的方法 ARC 苹果官方文档 下面用我自己的话介绍一下ARC,并将看文档过程中的疑问和答案写下来.下面有些是翻译,但 ...

随机推荐

  1. IE6兼容问题并解决总结

    1.使用声明你必须经常在html网页头部放置一个声明,推荐使用严格的标准.例如<!DOCTYPEHTMLPUBLIC“-//W3C//DTDHTML4.01//EN”   "http: ...

  2. run VLC in root

    sed -i 's/geteuid/getppid/' /usr/bin/vlc

  3. 在sqlserver中做fibonacci(斐波那契)规律运算

    --利用sqlserver来运算斐波那契规律 --利用事物与存储过程 declare @number intdeclare @A intdeclare @B intdeclare @C int set ...

  4. Java泛型学习笔记 - (四)有界类型参数

    1. 当我们希望对泛型的类型参数的类型进行限制的时候(好拗口), 我们就应该使用有界类型参数(Bounded Type Parameters). 有界类型参数使用extends关键字后面接上边界类型来 ...

  5. Unity3D 一个较常见的错误信息“rect[2] == rt->GetGLWidth() && rect[3] == rt->GetGLHeight()”

    rect[2] == rt->GetGLWidth() && rect[3] == rt->GetGLHeight() 这个错误信息的具体含义我还不太清楚.它出现以后会不停 ...

  6. iOS学习之git的使用

    SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器.集中式版本控 ...

  7. MySQL数据库4 - 查看数据表

    一. 查看表的基本结构 语法:DESCRIBE/DESC TABLE_NAME 查询结果含义: Field: 字段名 Type: 字段类型 Null: 是否可以为空 Key: 是否编制索引 defau ...

  8. jquery.hover()函数使用

    <script> $(document).ready(function (t) { $(".wadver li").hover(function(event) { $( ...

  9. #include <vector>用法之我见

    vector是一种顺序容器,事实上和数组差不多,但它比数组更优越.一般来说数组不能动态拓展,(何为动态拓展,即是说如果你知道你要存的数据的个数,你定义的存储数据的数组大小也就决定了,但是若你事先不知道 ...

  10. 安装Eclipse环境变量的配置,

    window7系统下的 步骤:    第一步:先安装JDK(记住你安装的位置)我安装在D:\Program Files\Java           目录下. 第二步:JDK安装好后,配置环境变量(重 ...