object->block->object(对象强引用块,块中捕获对象)
@interface TestViewController ()
@property (copy, nonatomic) void(^testMemeoryLeakBlock)(void);
@property (copy, nonatomic) NSString* aStr;
@end
@implementation TestViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aStr = @"test string";
__weak typeof(self) weakSelf = self;
self.testMemeoryLeakBlock = ^{
NSLog(@"%@",self.aStr);
NSLog(@"%@",_aStr); //block 也会捕获带下划线变量中self,
__strong typeof(weakSelf) strongSelf = weakSelf;
NSLog(@"%@",strongSelf.aStr);
NSLog(@"%@",strongSelf->_aStr);
};
}
- (void)dealloc{
//重写dealloc方法,观察对象是否被释放.
NSLog(@"dealloc method excute!");
}
[NSNotificationCenter defaultCenter]addObserverForName......
[NSNotificationCenter defaultCenter]addObserverForName...其实严格中没有出现循环引用,只是因为强引用造成对象无法释放.
@interface TestViewController ()
@property (strong, nonatomic) id observer;
@end
@implementation TestViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
//这里使用weakSelf时候,可以不用移除观察者.
__weak typeof(self) weakSelf = self;
self.observer =
[[NSNotificationCenter defaultCenter]addObserverForName:UIKeyboardDidHideNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * _Nonnull note) {
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf doSomeThing];
}];
}
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter]removeObserver:self.observer];
self.observer = nil; //如果是Strong 同时必须置nil
//[NSNotificationCenter defaultCenter]-->Observer --CopyBlock-->Self
}
- (void)dealloc{
NSLog(@"ViewController Dealloc!");
}
- (void)doSomeThing{
}
NSTimer scheduledTimerWithTimeInterval.....
NSTimer会保留其目标对象;知道定时器失效为止,调用invalidate方法可令timer失效,另外
一次性的timer任务执行完也会失效;反复执行的任务容易出现循环引用,如果其他对象又保留
timer一定会引入循环引用,可以引入块来打破这种保留环.
@interface NSTimer (invoke)
+(NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
block:(void(^)())block
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo;
@end
@implementation NSTimer (ste_invoke)
+(NSTimer*)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
block:(void(^)())aBlock
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo
{
return [
self scheduledTimerWithTimeInterval:ti
target:self
selector:@selector(ste_timerFireMethod:)
userInfo:[aBlock copy ]
repeats:yesOrNo
];
}
+(void)ste_timerFireMethod:(NSTimer*)timer
{
void(^block)() = timer.userInfo;
if (block) {
block();
}
}
@end
//使用的时候;也应该注意块的循环引用
Core Foundation 对象的内存管理
我们创建的Core Foundation 对象在ARC下由我们自己管理其生命周期(创建了就要对应有释放),当转换为Foundation框架下的对象时涉及到的对象方法有:
__bridge: 只做类型转换,不修改相关对象的引用计数,原来的Core Foundation 对象在不用时,需要调用CFRelease 方法.
__bridge_retained:类型转换后,将相关对象的引用计数加 1,原来的 Core Foundation 对象在不用时,需要调用CFRelease 方法.
__bridge_transfer:类型转换后,将该对象的引用计数交给ARC管理, Core Foundation 对象在不用时,不再需要调用 CFRelease 方法.
about block
对应的数据结构如下:
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
各个字段解释:
isa 指针,所有对象都有该指针,用于实现对象相关的功能.
flags,用于按 bit 位表示一些 block 的附加信息,本文后面介绍 block copy 的实现代码可以看到对该变量的使用.
reserved,保留变量.
invoke,函数指针,指向具体的 block 实现的函数调用地址.
descriptor, 表示该 block 的附加描述信息,主要是 size 大小,以及 copy 和 dispose 函数的指针.
variables,capture 过来的变量,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中.
在 Objective-C 语言中,一共有 3 种类型的 block:
_NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量.
_NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁.
_NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁.
对于block外的变量引用,block默认是将其复制到其数据结构中来实现访问的
对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的(能够修改值)
在 ARC 开启的情况下,将只会有 NSConcreteGlobalBlock 和 NSConcreteMallocBlock 类型的 block