有關ios中循環引用問題的總結

有關ios中循環引用問題的總結


如何幹掉環

在此處不講解循環引用是什麼,請自行搜索。ios內存分爲堆,棧,常量區,棧和常量區都是有系統管理的。

1.delegate與環

//ClassA: 
@protocol ClssADelegate  
- (void)fuck; 
@end 
@interface ClassA : UIViewController 
@property (nonatomic, strong) id  delegate; 
@end 
//ClassB: 
@interface ClassB () 
@property (nonatomic, strong) ClassA *classA; 
@end 
@implementation ClassB 
- (void)viewDidLoad {  
   [super viewDidLoad];   
      self.classA.delegate = self;
   }

解決方法:如上代碼,B強引用A,而A的delegate屬性指向B,這裏的delegate是用strong修飾的,所以A也會強引用B,這是一個典型的循環引用樣例。而解決其的方式大家也都耳熟能詳,即將delegate改爲弱引用

2.block與環

@interface ClassA () 
@property (nonatomic, copy) dispatch_block_t block; 
@property (nonatomic, assign) NSInteger tem; 
@end 
@implementation ClassA 
- (void)viewDidLoad {    
  self.block = ^{       
  };  
 }

解決方法:
@interface ClassA ()
@property (nonatomic, copy) dispatch_block_t block;
@property (nonatomic, assign) NSInteger tem;
@end
@implementation ClassA
- (void)viewDidLoad {
__weak typeof(self) weakSelf = self
weakSelf.tem = 1;
};
}

3.weakSelf的缺陷

//ClassB是一個UIViewController,假設從ClassA pushViewController將ClassB展示出來 
@interface ClassB () 
@property (nonatomic, copy) dispatch_block_t block; 
@property (nonatomic, strong) NSString *str; 
@end @implementation ClassB 
- (void)dealloc { } 
- (void)viewDidLoad {  
   [super viewDidLoad];   
   __weak typeof(self) weakSelf = self;  
            NSLog(@"%@", weakSelf.str);    
  };   
 }

解決方案:
這裏會有兩種情況:
• 若從A push到B,10s之內沒有pop回A的話,B中block會執行打印出來111。
• 若從A push到B,10s之內pop回A的話,B會立即執行dealloc,從而導致B中block打印出(null)。這種情況就是使用weakSelf的缺陷,可能會導致內存提前回收。
• @interface ClassB ()
@property (nonatomic, copy) dispatch_block_t block;
@property (nonatomic, strong) NSString *str;
@implementation ClassB
- (void)dealloc { }
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.block = ^{
__strong typeof(self) strongSelf = weakSelf; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});
};
self.block();
}
• 這麼做和直接用self有什麼區別,爲什麼不會有循環引用:外部的weakSelf是爲了打破環,從而使得沒有循環引用,而內部的strongSelf僅僅是個局部變量,存在棧中,會在block執行結束後回收,不會再造成循環引用。• 這麼做和使用weakSelf有什麼區別:唯一的區別就是多了一個strongSelf,而這裏的strongSelf會使ClassB的對象引用計數+1,使得ClassB pop到A的時候,並不會執行dealloc,因爲引用計數還不爲0,strongSelf仍持有ClassB,而在block執行完,局部的strongSelf纔會回收,此時ClassB dealloc。
這種做法其實已經可以解決所有問題了,但是:block內部必須使用strongSelf,很麻煩,不如直接使用self簡便。很容易在block內部不小心使用了self,這樣子還會引起循環引用,這種錯覺很難發現。

4.@weakify與@strongify

// 用法 
@interface ClassB () 
@property (nonatomic, copy) dispatch_block_t block; 
@property (nonatomic, strong) NSString *str; 
@end 
@implementation ClassB 
- (void)dealloc { } 
- (void)viewDidLoad {     
[super viewDidLoad];     
self.str = @"111";     
@weakify(self)     
self.block = ^{         
@strongify(self)         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{             
NSLog(@"%@", self.str);         
});     
};     
self.block();    
}
發佈了31 篇原創文章 · 獲贊 6 · 訪問量 9571
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章