iOS中的循环引用种类

1.属性传值循环引用

cell 添加到tableView上被tanleView强引用,cell中tableView被强引用,造成循环引用;

所以cell中tableView应该用weak关键字

- (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关键字循环引用

class A强引用BView, BView的代理指向A,因为delegate是strong关键字修饰,所以BView会强引用A的实例,造成循环引用

所以delegate关键字应该用weak修饰

定义:
@interface Class A: NSObject
@property (nonatomic, strong) BView *someView;
@property (nonatomic, strong) XXXDelegate delegate;

调用:
self.someView.delegate = self;

3.block捕获变量,循环引用

self持有block,block截获self(这一点我也没搞太明白),赋值会把block copy到堆上,持有相关变量,就是self持有block,block又持有self,形成循环引用

 self.block = ^{
      self.someProperty = xxx;
 } 

//解决方式
__weak typeOf(self) weakSelf = self;
self.block = ^{
    weakSelf.someProperty = xxx;
}

4.timer循环引用

viewController--->timer--->viewController
造成循环引用,使用weak不能够打破循环引用:由于timer已经加入到runloop中,而且是个重复循环操作,所以这个runloop好像停不下来了。。。所以timer也就无法释放,而他对当前的对象又是强引用。

创建中间层弱引用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
}

你可能感兴趣的:(iOS中的循环引用种类)