多线程(二)之block小结

时间:2022-07-04 08:43:03

http://www.cnblogs.com/lingzhiguiji/p/3701666.html

根据上述的博客小结如下:

Block的类型与内存管理
根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。
        NSGlobalBlock:类似函数,位于text段;
        NSStackBlock:位于栈内存,函数返回后Block将无效;
        NSMallocBlock:位于堆内存。

 无论MRC还是ARC,只要在block内部没有访问局部变量,那么这个block就存放在静态区(全局区,或者说是数据区)即NSGlobalBlock区

MRC模式下:block内部访问局部变量,这个block是存放到栈区的

ARC模式下:block内部访问局部变量,这个block是存放到堆区的

无论MRC还是ARC,局部变量copy后,这个block是存放到堆区的即NSMallocBlock

//MRC copy 使得栈区的block 拷贝到堆区,在旧版本的xcode中,strong不会拷贝到堆取,在新版本的xcode中,不管strong还是copy都在堆取,意图是让程序员少考虑内存问题,专注于业务逻辑

-(void)demo4{
//block 内修改外部变量,__block,把变量移到堆取
__block int number = 10;
NSLog(
@"11 %p",&number);

//拷贝到堆取,因为生命周期比较长,不会被立即释放
void(^myBlock)() = ^{

number
= 20;
NSLog(
@"22 %p",&number);
NSLog(
@"%d",number);

};

NSLog(
@"33 %p",&number);
NSLog(
@"%d---",number);

[self passBlock:myBlock];
}

但对于像:

    NSMutableString *str = [NSMutableString string];

    NSMutableArray *arr = [NSMutableArray array];

    NSMutableDictionary *dic = [NSMutableDictionary dictionary];

这三类定义的局部变量我不用在前面加__block,也能在block内部改变变量的值,因为,举例:str来说,str是存放在栈区的局部变量,但是实例化的对象却是在堆区中,所以我给这个对象改变值是可以直接改变的,但像上述例子中的int对象,显然是只存在栈区的,而我在block中是相当于copy了一份在堆区,那么,显然堆区中再去访问栈区以达到改变栈区值的目的是不可行的.

 

另外:__weak的目的就是为了避免循环引用,为什么会产生循环引用呢?因为

-(void)demo1{
//定义block,内部引用self
//方法中self->block->self
//方法执行完 block->self
//并不是所有在block内部使用self就会造成循环引用的问题(retain cycle)

void(^myBlock)() = ^{
NSLog(
@"%d,%@",self.number,self);
};

myBlock();
self.myblock2
= myBlock;
}

-(void)dealloc{
//套路:检查有没有循环引用,就查看dealloc是否被调用
//ps:循环引用不会调用这个方法,因为一直在互相引用,控制器没有被释放,没有循环引用才会调用这个方法,控制器再pop后会被释放掉.
NSLog(@"%s",__FUNCTION__);
}

这个代码中注意:myBlock 中打印了self说明,myBlock引用了控制器对象self,self.myblock2 = myBlock;这行代码又用myBlock给控制器的属性赋值说明,控制器对myBlock也进行了引用,所以互相引用就造成了循环引用,因此解决循环引用就如下代码所示(加__weak):

-(void)demo2{

//写法1 self->myBlock->weakVC
__weak ViewController *weakVC = self;
//写法2
__weak typeof(self) weakSelf = self;
void(^myBlock)() = ^{
NSLog(
@"%d",weakSelf.number);
};

self.myblock2
= myBlock;

}

 

 

 

 

 

 

 

 

 

 

//
// ViewController.m
// blockDemo
//
// Created by apple on 16/8/20.
// Copyright © 2016年 itcast. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

//MRC copy 使得栈区的block 拷贝到堆区,在旧版本的xcode中,strong不会拷贝到堆取,在新版本的xcode中,不管strong还是copy都在堆取,意图是让程序员少考虑内存问题,专注于业务逻辑
@property(nonatomic,strong) void(^myblock2)();

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

[self demo1];
}

-(void)demo7{
//MRC栈区的block 拷贝到堆区
int number = 10;
void(^myBlock)() = ^{
NSLog(
@"block %d",number);
};

self.myblock2
= myBlock;
NSLog(
@"%@",self.myblock2);

}


-(void)demo6{
/**
ARC 会自动的把block拷贝到堆取
* __NSMallocBlock__堆区block
MRC
__NSStackBlock__ 栈去block
*/
int number = 10;
void(^myBlock)() = ^{
NSLog(
@"block %d",number);
};

NSLog(
@"%@",myBlock);
}

-(void)demo5{
//block在内存中的位置
//__NSGlobalBlock__
void(^myBlock)() = ^{
NSLog(
@"block");
};

NSLog(
@"%@",myBlock);
}

-(void)demo4{
//block 内修改外部变量,__block,把变量移到堆取
__block int number = 10;
NSLog(
@"11 %p",&number);

//拷贝到堆取,因为生命周期比较长,不会被立即释放
void(^myBlock)() = ^{

number
= 20;
NSLog(
@"22 %p",&number);
NSLog(
@"%d",number);

};

NSLog(
@"33 %p",&number);
NSLog(
@"%d---",number);

[self passBlock:myBlock];
}

-(void)demo3{
//面试题:打印输出是? 10 block在声明的时候,拷贝了block内部涉及的变量,内存地址不唯一
int number = 10;
NSLog(
@"11 %p",&number);

void(^myBlock)() = ^{
NSLog(
@"%d",number);
NSLog(
@"2 %p",&number);
// number = 20;
// NSLog(@"block %p ",myBlock);

};

number
= 20;

[self passBlock:myBlock];

}

-(void)demo2{
//使用block在方法间传递参数
void(^myBlock)() = ^{
NSLog(
@"block");
};

[self passBlock:myBlock];
}

-(void)passBlock:(void(^)())block{
//调用传递过来的block
block();
}

- (void)demo1 {
//返回值 名字 参数 与函数或者方法很像
void(^myBlock)() = ^{
NSLog(
@"block");
};

NSLog(
@"%@",myBlock);
//调用block
myBlock();
}

@end