简单了解Block
2017-01-15 14:46
381 查看
block一般作为回调函数,形式:
int (^blk_t)(int)=^int (int count){return count+1;},对应的是^ 返回类型(参数列表){表达式};
用typedef如下:
typedef int (^blk)(int );
blk elk_t=^(int count){return count+1};
一、截获变量
block能截获变量,但不能修改变量,想修改变量,变量前面加__block,即使是静态变量,静态全局变量也不能修改。
block截获了指针可以使用它,不能截获C数组。
block可截获:变量(int a,double b),对象(实际是指针)
(block将截获的变量作为自己的成员变量进行访问,超出作用域释放)
二、Block实质
白皮书上说block是OC类对象,我觉得它更像结构体实例对象。结构体实例变量和普通变量一样,在栈上分配空间,超出作用域会被释放。
类:类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存
结构:结构是值类型在栈上分配。
Block结构体:
struct
__main_block_impl_0
{
struct
__block_impl impl;
struct
__main_block_desc_0 *Desc;
//截获的自动变量,作为block的成员变量
id array;//截获对象
//结构体的函数
__main_block_impl_0(void
*fp,struct
__main_block_desc_0 *desc,int
flags=0)
{
impl.isa=&NSConcreteStackBlock;
impl.Flags=flags;
impl.FuncPtr=fp;
Desc=desc;
}
};
定义完block之后,其实是创建了一个函数,在创建结构体的时候把函数的指针一起传给了block,所以之后可以拿出来调用。
有__block修饰的变量,实际上也是结构体实例。
struct
__Block_byref_val_0
{
__isa;
__forwarding;//指向自己的指针
__flags;
__size;
val;
//使用值
}
Block的struct
__main_block_impl_0结构体实例持有指向__block变量的struct
__Block_byref_val_0结构体实例指针。
三、Block的存储
Block实例和__block实例一般默认创建出来都是存储在栈上的,就像普通变量,
当作用域结束时,Block和__block会被复制到堆上,栈上__block变量的forwarding指针指向堆上的变量,这样就保证了变量同步。
需要复制的情况:
手动调用copy方法时;
Block作为函数的返回值;
将Block赋值给strong类型变量时;
在方法名中有usingBlock的Cocoa框架方法或GCD的API中传递Block时;
以上情况都会调用_Block_copy函数,除了以上情况下,推荐手动调用copy
复制实际调用的是_Block_copy方法,需要废弃时调用dispose方法。
Block截获两种变量,一种是_block修饰的变量,一种是对象(指针)
当Block调用copy函数时,Block持有截获对象的强引用,Block复制后强引用一直存在,所以被截获的对象不会被释放。
四、循环引用
最常见的是,类的成员变量有Block,Block函数里面引用self
破坏循环引用的方法:用__block变量tmp=self,Block里面用tmp,用完以后tmp置nil
用__weak变量tmp=self,Block里面用tmp
在ARC无效时,__block变量用完以后不用赋值nil,因为ARC无效,Block复制到堆上时,不会对__block变量retain。
int (^blk_t)(int)=^int (int count){return count+1;},对应的是^ 返回类型(参数列表){表达式};
用typedef如下:
typedef int (^blk)(int );
blk elk_t=^(int count){return count+1};
一、截获变量
block能截获变量,但不能修改变量,想修改变量,变量前面加__block,即使是静态变量,静态全局变量也不能修改。
block截获了指针可以使用它,不能截获C数组。
block可截获:变量(int a,double b),对象(实际是指针)
(block将截获的变量作为自己的成员变量进行访问,超出作用域释放)
二、Block实质
白皮书上说block是OC类对象,我觉得它更像结构体实例对象。结构体实例变量和普通变量一样,在栈上分配空间,超出作用域会被释放。
类:类是引用类型在堆上分配,类的实例进行赋值只是复制了引用,都指向同一段实际对象分配的内存
结构:结构是值类型在栈上分配。
Block结构体:
struct
__main_block_impl_0
{
struct
__block_impl impl;
struct
__main_block_desc_0 *Desc;
//截获的自动变量,作为block的成员变量
id array;//截获对象
//结构体的函数
__main_block_impl_0(void
*fp,struct
__main_block_desc_0 *desc,int
flags=0)
{
impl.isa=&NSConcreteStackBlock;
impl.Flags=flags;
impl.FuncPtr=fp;
Desc=desc;
}
};
定义完block之后,其实是创建了一个函数,在创建结构体的时候把函数的指针一起传给了block,所以之后可以拿出来调用。
有__block修饰的变量,实际上也是结构体实例。
struct
__Block_byref_val_0
{
__isa;
__forwarding;//指向自己的指针
__flags;
__size;
val;
//使用值
}
Block的struct
__main_block_impl_0结构体实例持有指向__block变量的struct
__Block_byref_val_0结构体实例指针。
三、Block的存储
Block实例和__block实例一般默认创建出来都是存储在栈上的,就像普通变量,
当作用域结束时,Block和__block会被复制到堆上,栈上__block变量的forwarding指针指向堆上的变量,这样就保证了变量同步。
需要复制的情况:
手动调用copy方法时;
Block作为函数的返回值;
将Block赋值给strong类型变量时;
在方法名中有usingBlock的Cocoa框架方法或GCD的API中传递Block时;
以上情况都会调用_Block_copy函数,除了以上情况下,推荐手动调用copy
复制实际调用的是_Block_copy方法,需要废弃时调用dispose方法。
Block截获两种变量,一种是_block修饰的变量,一种是对象(指针)
当Block调用copy函数时,Block持有截获对象的强引用,Block复制后强引用一直存在,所以被截获的对象不会被释放。
四、循环引用
最常见的是,类的成员变量有Block,Block函数里面引用self
破坏循环引用的方法:用__block变量tmp=self,Block里面用tmp,用完以后tmp置nil
用__weak变量tmp=self,Block里面用tmp
在ARC无效时,__block变量用完以后不用赋值nil,因为ARC无效,Block复制到堆上时,不会对__block变量retain。
相关文章推荐
- block(代码块)的一部分简单了解(一)
- block的简单了解
- 简单了解下POJO和PO
- 了解POP3协议,使用简单的代码监控pop3邮箱,或者不用代码,直接使用telnet
- 学习NUnit测试2(简单的Nunit使用,用于了解Nunit)
- 了解POP3协议,使用简单的代码监控pop3邮箱,或者不用代码,直接使用telnet
- 了解POP3协议,使用简单的代码监控pop3邮箱,或者不用代
- Struts 1 学习笔记-1(简单登录模块的实现,Struts初步了解)
- 了解 Java EE 5 -- 重要增强功能意味着更快、更容易、更简单地开发企业应用程序
- 简单了解下POJO和PO
- 简单了解下POJO和PO
- 了解POP3协议,使用简单的代码监控pop3邮箱
- java.util.Locale简单了解
- c++语言程序设计超级简单了解
- 学习NUnit测试1(简单的Nunit使用,用于了解Nunit)
- 最最最简单的了解 .Net 程序是如何启动的
- 简单了解Timer与TimerTask
- linux下网络配置的简单了解
- 简单了解htmlparser
- 简单了解Timer与TimerTask