object->block->object(對象強引用塊,塊中捕獲對象)objective-c
@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.....app
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框架下的對象時涉及到的對象方法有:框架
對應的數據結構以下:ide
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 時會被銷燬.ui
對於block外的變量引用,block默認是將其複製到其數據結構中來實現訪問的
對於用 __block 修飾的外部變量引用,block 是複製其引用地址來實現訪問的(可以修改值)
在 ARC 開啓的狀況下,將只會有 NSConcreteGlobalBlock 和 NSConcreteMallocBlock 類型的 blockatom
參考連接:
https://stackoverflow.com/que...
http://blog.parse.com/learn/e...
http://blog.devtang.com/2013/...spa