重新思考自动内存管理(ARC)

129 阅读2分钟

**思考问题:weak指针是干嘛的,weak指针与ARC有什么关系 **

class MessageDispatcher { 
  // 使用 NSHashTable 存储监听器,支持弱引用 
  private var listeners =NSHashTable<MessageListener>.weakObjects() 
  // 注册监听器 
  func addListener(_ listenerMessageListener) { listeners.add(listener) }
  // 注销监听器 
  func removeListener(_ listenerMessageListener) { listeners.remove(listener) }
  // 派发消息 
  func dispatchMessage(_ messageString) { 
    for listener in listeners.allObjects { 
     listener.onMessageReceived(message) 
    } 
  } 
}

protocol MessageListenerAnyObject {
   func onMessageReceived(_ messageString) 
}


class XXXViewModel:MessageListener {
    init(){
       mesageDispatcher.addListener(self)
    }
    
    func onMessageReceived(_ messageString) {
    
    }
    deinit {
       messageDispatcher.removeListener(self)
    }
}

以上是IMSDK消息派发器中一段常见的代码,有个疑问以上的NSHashTable为什么要用weak类型的指针管理监听器呢。以下是几种常见的见解:(百分之九十九的开发者只知道要用weak,因为别人用的是weak呀,但是没有人思考过为什么要用weak,用weak指针他的指导思想是什么)

1.有人说是因为项目中所有的三方sdk或者自己的sdk都是用weak指针的。

2.有人说用强引用也可以呀,派发器已经提供了注册/注销能力,谁注册谁注销也符合常理。

3.还有小可爱说因为andriod平台的IMSDK里面的消息派发器用的就是强引用listener监听器的,为了保持与andriod平台一致。

image.png

那他的本质是什么原因要用weak指针呢,其实这里用weak指针是从内存自动管理思想(ARC) 出发的。自动内存管理ARC的思想是:一个大A对象里面持有a1,a2,a3子对象,我们希望随着A对象的内存被回收了后,a1,a2,a3字对象的内存能自动回收,而不需要大A对象做额外的内存管理逻辑去管理a1,a2,a3子对象的内存,因为如果我们需要手动管理一个a1子对象的内存(MRC),a2,a3子对象内存仍然自动管理(ARC)虽然也可以;但是我们无法保证后序代码扩展的a4,a5,a6子对象是否要MRC呢。所以这里又回到事情的最开始出发点了,weak指针本来就是为了实现ARC思想的辅助一个工具,所以这里才需要用weak指针。

基于以上,回应截图里面的第三点吧,第一二点说了跟没说一样;关于第三点正是因为IMSDK消息派发器无法统一管理其生命周期,所以sdk派发器要用weak指针引用监听者。很多小可爱用中文描述要做的东西跟自己用代码实现的东西是完全背道而驰的,所以请各位程序员带着脑子与思想去写代码吧