BLOCK
block的描述: 他是类似函数指针的一个代码块的内联封装, 他可以将一个函数体作为对象传递
block的本质: 对象
block的效率: 高于函数调用
声明一个block
返回值 (^名称)(以”逗号”分割的参数), 参数部分可以不写参数名只写类型
范例:
void (^myFirstBlock)( int a, NSString *s, UIButton *button )
BOOL (^mySecondBlock)(void)
NSString * (^myThirdBlock)(CGFloat, float)
定义一个block
^可省略的返回值(以”逗号”分割的参数){代码块}
范例:
^void(int a){NSLog(@"一个int参数, 无返回值的block"); }
^{ NSLog(@"一个无参数,无返回值的block"); }
^int(int a, int b){ NSLog( @"一个两个int参数, 返回两个数相加的block, 结果%d", a + b ); return a + b; }
block作为函数参数
block作为参数, 参数名后缀, 类型格式为: ( 返回值(^)(参数) )block名
范例:
- (void)test:(int(^)(int))paramBlock
{
NSLog( @"打印block返回结果:%d", paramBlock(10));
}
block作为参数的函数调用:
将block定义部分或将block对象传入函数调用的参数部分
范例:
[self test:^(int a){
return a * a;
}];
__block:
block只能只读的访问局部变量, 若需要修改局部变量, 需要通过__block修饰该变量, 该修饰符会使block自动复制该对象的指针,即指针拷贝, 当对该对象执行写操作时, 其实就是操作其指针指向的对象进行操作.
若不加该修饰符, block仅自动复制需要访问的局部变量的值副本(值拷贝), 因此只能进行只读操作.
__weak:
使用block特别要注意的一点就是防止循环引用的发生, block作为一个对象被持有者持有,若block内部也持有该持有者将会导致循环引用,导致相互持有, 永远无法销毁彼此的内存问题, 若不能规避该问题, 则需要通过使用__weak修饰 block要访问的持有者变量, 防止循环引用的发生. 尤其是block所在的self.
__strong
该修饰符在block内的主要作用是防止__weak修饰的指针在block运行期间被外部销毁, 导致block无法顺利完成原定功能. 所以当访问的外部变量用__weak修饰时, block内部最好再有一个__strong修饰的同类型指针指向__weak指针, 这样就可以确保, 在block内部的这个指针可以运行完成. 随着block运行完成, __strong修饰的指针也将自动销毁, 进而__weak指针也会自动置nil.
block外部变量访问
block可以访问和修改全局变量
block只能只读的访问局部变量(值传递, block内部复制了一个副本), 若加了__block修饰, 就改为引用传递,可修改局部变量
block底层浅谈
block本身包含一个结构体
struct __block_impl
{
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
}
block分为三种类型, __block_impl的isa指针负责标记block类型
_NSConcreteGlobalBlock: 全局静态block, 当block内不访问任何外部变量, 或者访问的是全局作用域,成员变量的, 属于该类型, 内存管理方式和函数一致
_NSConcreteStackBlock 栈block, 由系统管理内存, 函数返回时销毁, 访问的外部变量由block从栈上copy到堆上, 保证了作用域结束后, block仍然可以访问
_NSConcreteMallocBlock 堆block, 由开发者控制, 引用计数为0时销毁
block几种自身copy的情况, 若触发一下情况, block将自动拷贝自身到堆中, 确保自身作用域内的变量的生命周期更长久
1.显式执行copy, [block copy];
2.block作为返回值的时候
3.block被赋值给__strong类型的对象或者block的内部变量时
4.block作为参数传入带有usingBlock的CocoaFramework方法
5. block作为参数传入GCD的API时
其他:
__typeof, __typeof__, typeof 这三个关键字实现了一个相同的功能, 获取参数的类型名称并返回
UIViewController *vc;
__typeof(vc) vc2;
这样就可以在不知道vc指针类型的情况下, 再声明一个同类型的vc2