iOS 内存泄漏的元凶——循环引用

项目中使用MLeaksFinder(原理请戳我)检测内存泄漏,十分方便和直观。会精确到某个VC,某个View。

iOS 内存泄漏的元凶——循环引用_第1张图片
MLeaksFinder发现内存泄漏的弹窗

内存泄漏大多由于循环引用,导致循环引用的几种类型:

  • Block (基本项目中这种情况是最多的)
  • delegate
  • Timer
  • Notification

Block循环引用(最常见)

  • block 会被copy, 并retain block中引用的对象。为打破引用循环,用weak修饰引用的对象。
  • [weak self][weak cell] 之后guard let strongSelf = self else {return}strongSelf为什么不会造成引用循环。 因为strongSelf在block中声明,相当于一个临时变量,block执行完毕后,会被释放掉,不会循环引用。
  • demo
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "XXTestCell", for: indexPath) as! XXTestCell
        // 防止引用循环
        // 1. 重新获取一个局部cell
//        cell.buttonCallBack = {
//            let cell = tableView.cellForRow(at: indexPath) as? XXTestCell
//            cell?.configureLabel(with: "110")
//        }
        
        // 2.不用重新获取,[weak cell]方式。以前没用过,用了之后发现很好用(推荐这种)
        cell.buttonCallBack = { [weak cell] in
            cell?.configureLabel(with: "110")
        }

// 3. 引用循环
        cell.buttonCallBack = {
            cell.configureLabel(with: "110")
        }
        
        return cell
    }

delegate循环引用

谨记用weak来修饰delegate一般不会有啥问题了

Timer循环引用

解除Timer循环引用请戳我

Notification循环引用

  1. 一般平常注册通知这么写,没啥问题
NotificationCenter.default.addObserver(self, selector: #selector(receivedRotation), name: UIDevice.orientationDidChangeNotification, object: nil)

@objc func receivedRotation(){
}
  1. 突然看到一位童鞋写了这样的代码,对,就是循环引用了。


    image.png
  2. 修改,闭包发生的内存泄漏最好解,一般用[weak self],即可打破循环引用:

NotificationCenter.default.addObserver(forName: .userLoggedIn, object: nil, queue: OperationQueue.main) { [weak self] (noti) in
            self?.swiftTruckSettins(self?.avoidTollsSwitch)
}
  1. 原因,先看此方法描述
- (id )addObserverForName:(nullable NSNotificationName)name object:(nullable id)obj queue:(nullable NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0));
    // The return value is retained by the system, and should be held onto by the caller in
    // order to remove the observer with removeObserver: later, to stop observation.

文档中明确说明了,调用者会持有返回的observer对象。 VC -> observer -> block, block -> VC。具体验证详情请戳我

注:

  • MLeaksFinder检测textfiled会误判泄漏,其实没有哦。

你可能感兴趣的:(iOS 内存泄漏的元凶——循环引用)