一、缘由
有时候会因为循环引用导致对象无法释放时,会导致内存泄漏问题,使程序内存无法及时释放而内存增加。有时候我们想在block块中修改外部变量或者对象的值或属性,这些问题和需求使我们不得不去想办法更好地解决,这个时候我们会想到的是使用__weak和__block进行修饰。
二、block定义
在进行__weak和__block使用之前,我们先来对block块的基本定义回味一下,让接下来阅读起来更加地流畅。
定义如下:void(^myBlock)(void) 返回类型(^myBlock)(参数类型)
也可以使用typedef来给复杂的Block定义别名,写法为:typedef void(^myBlock)(void);
三、?
__weak typeof(self) weakSelf = self; // MRC下对象同样不会被释放
self.block = ^{
NSLog(@"%@", NSStringFromClass([weakSelf class]));
};
self.block();
案例一:__weak避免循环引用。当我们使用block块的时候,很容易就导致循环引用,可以使用__weak定义一个弱引用weakSelf,由于弱引用不持有对象实例,当对象不被使用时,weakSelf将会释放并被系统所回收,使得block块不再强引用着self不释放,避免出现循环引用。
__block int num = 10; // __block可以修饰对象与基本数据类型
// __weak int num = 10; // __weak只能修饰对象,不能修饰基本数据类型
self.block = ^{
num++;
NSLog(@"内部值:%d", num);
};
self.block();
NSLog(@"外部值:%d", num);
案例二:使用__block修饰基本变量类型。当没有使用__block修饰变量num时,此时的num变量则可读不可写,因为此时Block块内部会将变量做处理,重新生成一个变量指向num,使得在Block块内外操作其实不是相同的num变量。当使用了__block变量时,Block块内部将使用此变量,不再生成新的变量,所以此时外部对变量num的操作也会改变Block块num变量的值。
//JZPerson.h
@property (copy, nonatomic) NSString* name;
//ViewController.m 实现
JZPerson* person = [[JZPerson alloc]init];
person.name = @"mjz";
__weak JZPerson* weakPerson = person;
NSLog(@"地址:%p---%p", person, &person);
NSLog(@"地址:%p---%p", weakPerson, &weakPerson);
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
__strong JZPerson* strongPerson = weakPerson;
weakPerson.name = @"tsy";
NSLog(@"person: %@", person.name);
NSLog(@"weakPerson: %@", weakPerson.name);
NSLog(@"strongPerson1: %@", strongPerson.name);
sleep(3);
NSLog(@"%@", weakPerson.name);
NSLog(@"strongPerson2: %@", strongPerson.name);
});
NSLog(@"%@", weakPerson.name);
person = nil;
sleep(5);
NSLog(@"end: %@", weakPerson.name);
案例三:使用__strong强引用着__weak。__strong使得在使用对象期间,防止对象被释放后导致程序出错。在使用期间强引用着对象,__strong对象使用完毕后会被系统回收,成功地防止了对象在外部被不小心释放导致地问题。
总结:
__strong与__weak起到修饰符的作用,类似于属性关键字,强引用与弱引用;
__block可以修饰对象和基本数据类型;
__weak只能修饰对象,不能修饰基本数据类型;
__weak直接修饰生成对象会被释放,__block则不会。
参考阅读:
2. 《Objective-C高级编程 iOS与OS X多线程和内存管理》