原文参考博文:

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. <![CDATA[]]>作用

    <![CDATA[]]>的作用是让XML解析器将标签中的字符串当作普通文本对待,以防止某些字符串对XML格式造成破坏.

  2. clistctrl失去焦点高亮显示选中行

    clistctrl失去焦点高亮显示选中行 响应两个消息 NM_SETFOCUS,NM_KILLFOCUS void CDatabaseParseDlg::OnNMKillfocusListGroup( ...

  3. Sql Server 查看表修改记录

    可以尝试如下建议:1.可以使用默认的Log工具或者第三方的(比如:LiteSpeed)的工具.2.做Trace机制,下次出现问题可以溯源.3.一个简单的办法: --Step #1: USE DBNam ...

  4. 在Eclipse for mac中配置tomcat,使web项目自动部署到tomcat

    jdk.tomcat的配置就不多说了,网上一大堆. 一.发现问题 在eclipse中新建Dynamic Web Project,配置好本地的tomcat并写好代码后选择Run on Server,但运 ...

  5. 关闭键盘导致tableView:didSelectRowAtIndexPath:失效解决办法

    今天公司的小兄弟问了tableView:didSelectRowAtIndexPath:不能执行的问题. 从经验看觉得可能是控制器没有成为tableView的代理所致.但代码中已经添加了代码 _tab ...

  6. matlab初学之strcat、num2str

    文章出处: http://blog.sina.com.cn/s/blog_6fb8aa0d01019id5.html http://wenda.so.com/q/1439143662729624 ht ...

  7. 《1---关于解决MySQL在控制台插入中文乱码问题》

    说明:以下所有操作都是基于我个人的电脑及示例,读者可以参考我这个解决过程,去解决自己的问题,如有其它疑问,欢迎留言交流. 首先来看看我遇到的问题: [1]查看数据库: [2]使用test数据库: [3 ...

  8. layoutSubviews 与 drawRect

    layoutSubviews总结 ios layout机制相关方法 - (CGSize)sizeThatFits:(CGSize)size- (void)sizeToFit——————- - (voi ...

  9. C# 3D效果饼状图的绘制

    第一步:放置图表控件 拖动工具栏的Chart控件到界面上 然后选中控件,设置Series属性,将ChartType属性改为pie 第三步:设置3D效果 选择控件,设置ChartArea属性,如下 设置 ...

  10. JAVA Arrays.binarySearch

    转自:http://blog.csdn.net/somebodydie/article/details/8229343 package com.jaky; import java.util.*; pu ...