弱引用对象

struct WeakObject<T: AnyObject>: Equatable, Hashable {
    private let identifier: ObjectIdentifier
    weak var object: T?
    init(_ object: T) {
        self.object = object
        self.identifier = ObjectIdentifier(object)
    }
    
    var hashValue: Int {
        return self.identifier.hashValue
    }
    
    static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

弱引用数组

struct WeakObjectSet<T: AnyObject>: Sequence {
   
    var objects: Set<WeakObject<T>>
    
    init() {
        self.objects = Set<WeakObject<T>>([])
    }
    
    init(_ object: T) {
        self.objects = Set<WeakObject<T>>([WeakObject(object)])
    }
    
    init(_ objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject($0) })
    }
    
    var allObjects: [T] {
        #if swift(>=4.1)
            return objects.compactMap { $0.object }
        #else
            return objects.flatMap { $0.object }
        #endif
    }
    
    func contains(_ object: T) -> Bool {
        return self.objects.contains(WeakObject(object))
    }
    
    mutating func add(_ object: T) {
        //prevent ObjectIdentifier be reused
        if self.contains(object) {
            self.remove(object)
        }
        self.objects.insert(WeakObject(object))
    }
    
    mutating func add(_ objects: [T]) {
        objects.forEach { self.add($0) }
    }
    
    mutating func remove(_ object: T) {
        self.objects.remove(WeakObject<T>(object))
    }
    
    mutating func remove(_ objects: [T]) {
        objects.forEach { self.remove($0) }
    }
    // Sequence Protocol 只有一个必须要实现的方法makeIterator()
    func makeIterator() -> AnyIterator<T> {
        let objects = self.allObjects
        var index = 0
        // 需要返回一个 Iterator,它是一个 IteratorProtocol 类型
        return AnyIterator {
            defer { index += 1 }
            return index < objects.count ? objects[index] : nil
        }
    }
}

Iterator 在 Swift 3.1 标准库中即为 IteratorProtocol,它用来为 Sequence 提供迭代能力。对于 Sequence,我们可以用for-in来迭代其中的元素,其实for-in的背后是 IteratorProtocol 在起作用

以下实现,与即时通讯接受消息实现类似,也可代替通知

public class Broadcaster {
    
    /// 静态的可变字典,把协议名称作为key,把代理存放到对应的弱引用数组中
    fileprivate static var observersDic = [String: Any]()
    
    // Dispatch Barrier 解决多线程并发读写同一个资源发生死锁
    // 需要注意 dispatch_barrier_async 只在自己创建的队列上有这种作用,在全局并发队列和串行队列上,效果和 dispatch_sync 一样
    // 自定义全局队列
    fileprivate static let notificationQueue = DispatchQueue(label: "com.swift.notification.center.dispatch.queue", attributes: .concurrent)


    // 面向协议开发思路
    public static func register<T>(_ protocolType: T.Type, observer: T) {
        let key = "\(protocolType)"
        safeSet(key: key, object: observer as AnyObject)
    }
    
    public static func unregister<T>(_ protocolType: T.Type, observer: T) {
        let key = "\(protocolType)"
        safeRemove(key: key, object: observer as AnyObject)
    }
    
    
    /// Remove all observers which comform to the protocol
    public static func unregister<T>(_ protocolType: T.Type) {
        let key = "\(protocolType)"
        safeRemove(key: key)
    }
    
    public static func notify<T>(_ protocolType: T.Type, block: @escaping (T) -> Void ) {
        
        let key = "\(protocolType)"
        guard let objectSet = safeGetObjectSet(key: key) else {
            return
        }
        // 此处执行大部分是UI界面刷新,因此要切换到UI线程
        for observer in objectSet {
            if let observer = observer as? T {
                DispatchQueue.main.async {
                    block(observer)
                }
            }
        }
    }
}

private extension Broadcaster {
    
    static func safeSet(key: String, object: AnyObject) {
        notificationQueue.async(flags: .barrier) {
            if var set = observersDic[key] as? WeakObjectSet<AnyObject> {
                set.add(object)
                observersDic[key] = set
            }else{
                observersDic[key] = WeakObjectSet(object)
            }
        }
    }
    
    static func safeRemove(key: String, object: AnyObject) {
        notificationQueue.async(flags: .barrier) {
            if var set = observersDic[key] as? WeakObjectSet<AnyObject> {
                set.remove(object)
                observersDic[key] = set
            }
        }
    }
    
    static func safeRemove(key: String) {
        notificationQueue.async(flags: .barrier) {
            observersDic.removeValue(forKey: key)
        }
    }
    
    static func safeGetObjectSet(key: String) -> WeakObjectSet<AnyObject>? {
        var objectSet: WeakObjectSet<AnyObject>?
        // 同步执行 {number = 1, name = main}
        // 如果当前线程是异步 {number = 3, name = (null)}
        notificationQueue.sync { 
           // printLog(Thread.current)
            objectSet = observersDic[key] as? WeakObjectSet<AnyObject>
        }
        return objectSet
    }
}

与通知相比,传值非常方便

使用示例:

// 声明协议
protocol UpdateTitle {
    func updateWithNewTitle(title: String)
}

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 给对象注册协议
    Broadcaster.register(UpdateTitle.self, observer: self)
}
// 实现协议
extension FirstViewController: UpdateTitle{
    func updateWithNewTitle(title: String) {
        titleLabel.text = title
    }
}

// 其他地方的调用
@IBAction func updateTitle(sender: UIButton) {
    Broadcaster.notify(UpdateTitle.self) {
        printLog(Thread.current)
        $0.updateWithNewTitle(title: self.textField.text ?? "")
    } 
}

总结:

原文地址github下载地址