Combine进化之路4——Subject

有些时候我们想要随时在Publisher插入值来通知订阅者(Rx中也提供了Subject类型实现)。
Subject通常是一个中间代理,既可以作为Publisher,也可以作为Observer。
官方给出的定义如下:

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public protocol Subject<Output, Failure> : AnyObject, Publisher {

    /// Sends a value to the subscriber.
    ///
    /// - Parameter value: The value to send.
    func send(_ value: Self.Output)

    /// Sends a completion signal to the subscriber.
    ///
    /// - Parameter completion: A `Completion` instance which indicates whether publishing has finished normally or failed with an error.
    func send(completion: Subscribers.Completion<Self.Failure>)

    /// Sends a subscription to the subscriber.
    ///
    /// This call provides the ``Subject`` an opportunity to establish demand for any new upstream subscriptions.
    ///
    /// - Parameter subscription: The subscription instance through which the subscriber can request elements.
    func send(subscription: Subscription)
}
  • 作为Subscriber时,可以通过Publisher的subscribe(_:Subject)方法订阅某个Publisher。
  • 作为Publisher时,可以通过send方法,在数据流中随时插入数据。目前在Combine中,有三个已经实现的Subject:AnySubjectCurrentValueSubjectPassthroughSubject

利用Subject可以很轻松地将现在已有的代码的一部分转成Reactive。

import UIKit
import Combine

class SubjectViewController: UIViewController {
    
    let cm2 = CbContentManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .cyan
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        
        // 方式1
//        let cm = ContentManager(delegate: self, content: .red)
//        cm.getContent()
        
        // 方式2
        let _ = cm2.content.sink {
            print("comp: \($0)")
        } receiveValue: {
            print("receive: \($0)")
            self.view.backgroundColor = $0
        }
        cm2.getContent()
        
    }
}

extension SubjectViewController: ContentManagerDelegate {
    func contentDidChange(_ content: UIColor) {
        view.backgroundColor = content
    }
    
    
}




//MARK: - 方式一 代理响应
protocol ContentManagerDelegate {
    func contentDidChange(_ content: UIColor)
}
class ContentManager: NSObject {
    var delegate: ContentManagerDelegate
    
    var content: UIColor {
        didSet {
            delegate.contentDidChange(content)
        }
    }
    
    
    init(delegate: ContentManagerDelegate, content: UIColor) {
        self.delegate = delegate
        self.content = content
    }
    
    
    func getContent() {
        content = UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: CGFloat(arc4random()%6)/5.0+0.5)
    }
}



//MARK: - 方式2 响应
class CbContentManager {
    var content = CurrentValueSubject<UIColor, NSError>(.orange)
    
    func getContent() {
        content.value = UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: CGFloat(arc4random()%6)/5.0+0.5)
        content.send(UIColor(red: CGFloat(arc4random()%256)/255.0, green: CGFloat(arc4random()%256)/255.0, blue: CGFloat(arc4random()%256)/255.0, alpha: CGFloat(arc4random()%6)/5.0+0.5))
    }
}

CurrentValueSubject就是包含一个初始值,并且会在每次值变化的时候发送一个消息,这个值会保存,可以很方便的用来替换Property Observer。
PassthroughSubject和CurrentValueSubject几乎一样,只是没有初始值,也不会保存任何值。

Combine进化之路合集

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容