天天看點

有關ios中循環引用問題的總結有關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,這樣子還會引起循環引用,這種錯覺很難發現。

[email protected]與@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)( * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{             
NSLog(@"%@", self.str);         
});     
};     
self.block();    
}