1.屬性傳值循環(huán)引用
cell 添加到tableView上被tanleView強(qiáng)引用,cell中tableView被強(qiáng)引用,造成循環(huán)引用;
所以cell中tableView應(yīng)該用weak關(guān)鍵字
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TabelViewCell *cell = ...
cell.tableView = tableView;
return cell;
}
@interface TableViewCell: UITableViewCell
@property (nonatomic, strong) UITableView *tableView;
@end
2.delegate屬性用strong關(guān)鍵字循環(huán)引用
class A強(qiáng)引用BView, BView的代理指向A,因?yàn)閐elegate是strong關(guān)鍵字修飾,所以BView會強(qiáng)引用A的實(shí)例,造成循環(huán)引用
所以delegate關(guān)鍵字應(yīng)該用weak修飾
定義:
@interface Class A: NSObject
@property (nonatomic, strong) BView *someView;
@property (nonatomic, strong) XXXDelegate delegate;
調(diào)用:
self.someView.delegate = self;
3.block捕獲變量,循環(huán)引用
self持有block,block截獲self(這一點(diǎn)我也沒搞太明白),賦值會把block copy到堆上,持有相關(guān)變量,就是self持有block,block又持有self,形成循環(huán)引用
self.block = ^{
self.someProperty = xxx;
}
//解決方式
__weak typeOf(self) weakSelf = self;
self.block = ^{
weakSelf.someProperty = xxx;
}
4.timer循環(huán)引用
viewController--->timer--->viewController
造成循環(huán)引用,使用weak不能夠打破循環(huán)引用:由于timer已經(jīng)加入到runloop中,而且是個(gè)重復(fù)循環(huán)操作,所以這個(gè)runloop好像停不下來了。。。所以timer也就無法釋放,而他對當(dāng)前的對象又是強(qiáng)引用。
創(chuàng)建中間層弱引用timer,在deinit銷毀timer
class TimerProxy{
private weak var target:AnyObject?//一定要是弱引用
private var selector:Selector?
init(with target:AnyObject, selector:Selector) {
self.target = target
self.selector = selector
}
@objc public func executeSelector(){
if (target != nil) && (selector != nil) {
target?.perform(selector, with: nil)
}
}
deinit {
debugPrint("TimerProxy已釋放")
}
}
使用方法:
let proxy = TimerProxy.init(with: self, selector: #selector(timerDo))
timer = Timer.init(timeInterval: 1, target: proxy, selector: #selector(proxy.executeSelector), userInfo: nil, repeats: true)
RunLoop.current.add(timer!, forMode: .common)
deinit {
debugPrint("TimerViewController已釋放")
timer?.invalidate()
timer = nil
}