Block
-
创建的三种形式
-
没有参数,没有返回值的block
void (^myBlock1))() = ^{};
myBlock1();
-
有参数,没有返回值的block
void (^myBlock2)(int a) = ^(int a){};
myBlock2();
^(int a){}; 也可写作 ^void(int a){};
-
有参数,有返回值的block
int (^myBlock3)(int a, int b) = ^(int a, int b){};
int a = myBlock3(1, 2);
类中@implementation 中可以书写C语言函数,并可以被调用
-
-
将block作为参数或者返回值,利用typedef
typedef void(^TestBlock)(int a, int b);
-
作为参数
- (void) method_testBlock1: (TestBlock)block{
block(100, 200); //最后调用这个代码块去执行
};
-
作为返回值
- (TestBlock) method_testBlock2{
return ^void(int a, int b){
NSLog(@" method_testBlock2 a*b = %d", a*b);
};
};
- 注意:见到 ^ 符号则要写方法体,见到返回值类型则只需调用执行
-
-
block的应用场景
- 作为方法参数
- 作为属性使用,同委托一样可以进行类与类之间的通讯
- 作为函数使用
-
对外部变量的使用或改变
-
使用局部变量
- block内部使用局部变量,会将变量值拷贝一份到block中,那么block的变量就不再是原来的变量,已变成了呀un来变量的副本,所以外部修改不会影响block内部的值
- 使用__block修饰的变量,block内部使用时不会进行拷贝,使用的还是同一个变量,所以在外部修改后会影响block内部的值
-
使用全局变量
- block内部要对全局变量修改就不需要使用__block来修饰了
-
-
iOS 堆(heap)和栈(stack)的理解
- 栈区:由编译器自动分配释放,存放对象指针、局部变量、局部参数。其操作方式类似数据结构中的栈
- 堆区:一般由程序员分配释放,存放对象指针指向的内容
- 栈区中存储的对象内存长度固定不可修改,堆区中的对象内存长度可变
- 全局区、静态区:存放全局变量、静态变量
- 常量区:存放常量
-
内存管理
- block有三种存储位置,①__NSGlobalBlock(全局区block,类似于函数)、②__NSStackBlock__(栈区的block),当block使用了局部变量、全局变量……就会形成栈区的block、③__NSMallocBlock__(堆区的block)当block进行copy操作,是将block从栈区拷贝到堆区,堆区的block需要管理内存
- 在block中使用了对象(未修改对象)时,Block_copy(block)或者[block copy]只会使局部对象引用计数+1、全局对象不做任何处理、(对象属性、实例对象)所在的对象(self)引用计数+1,最终目的是让block持有这些对象
-
解决循环引用
- __block修饰符:①被__block修饰的对象可在block进行copy时,其自身的引用计数不会被+1。②被__block修饰的元素可以在block中被修饰
-
在A类中有一个属性block,类型是代码块。然A类中又有一个实例方法,方法中对属性block赋值,然block被赋予的代码块又使用self,并对A类中的另一个NSString *类型的属性str赋值了,这就导致了相互引用
解决方案:
-
在MRC(手动内存管理)中
- __block typeof(self) blockSelf = self;
- __block A *a = self;
-
在ARC(自动内存管理)中
- __weak typeof(self)weakSelf = self;
- 此处必须使用__weak而不能使用__block,因为使用__block去修饰,weakSelf(self)的引用计数+1。在当前对象的实例方法的block中,使用当前对象的str属性时,因属性本省就被存储,在堆区中,所以不需要去copy,又因是copy去修饰这个block类型的属性,所以当不需要copy时,__block = [block copy]会选择浅赋值,即只传指针,不对内容进行copy,也就是当前对象的str属性未被copy
- 注意:weakSelf.str = @"……..";这当中weakSelf是被使用了,str则是去修改。
-