美文网首页SwiftUI
Combine-Foundation中的Publisher

Combine-Foundation中的Publisher

作者: YungFan | 来源:发表于2020-03-20 13:45 被阅读0次

    为了方便使用,Foundation 为 iOS 开发中的几个常见操作提供了直接获取 Publisher 的方式。

    • URLSession Publisher
    • Timer Publisher
    • Notification Publisher
    • KVO
    • @Published

    URLSession Publisher

    这是 URLSession 新增的一种网络 API,通过这个 API 可以更加简单的完成网络请求数据转换等操作。

    // 服务器返回的数据对应的Model
    struct NewsModel: Codable {
        var reason: String
        var error_code: Int
        var result:Result
    }
    
    struct Result: Codable {
        var stat: String
        var data:[DataItem]
    }
    
    // 实现Hashable,List中的数据必须实现
    struct DataItem: Codable, Hashable {
        var title: String
        var date: String
        var category: String
        var author_name: String
        var url: String
    }
    
    
    let url = URL(string: "http://v.juhe.cn/toutiao/index?type=top&key=d1287290b45a69656de361382bc56dcd")
    let request = URLRequest(url: url!)
    let session = URLSession.shared
    let backgroundQueue = DispatchQueue.global()
    
    let dataPublisher = session.dataTaskPublisher(for: request)
        .retry(5)
        .timeout(5, scheduler: backgroundQueue)
        .map{$0.data}
        .decode(type: NewsModel.self, decoder: JSONDecoder())
        .subscribe(on: backgroundQueue)
        .eraseToAnyPublisher()
    
    let subscription = dataPublisher.receive(on: DispatchQueue.main)
        .sink(receiveCompletion: {_ in }) {
            newsModel in
            print(newsModel.result.data)
    }
    

    Timer Publisher

    当收到 Subscriber 请求时,大部分的 Publisher 会立即提供数据, 如 Just。但有一种符合 ConnectablePublisher 协议的 Publisher,它需要某种机制机制来启动数据流。而 Timer.TimerPublisher 就是这种类型的 Publisher。ConnectablePublisher 不同于普通的 Publisher,需要明确地对其调用connect() 或者 autoconnect()方法,它才会开始发送数据。

    • autoconnect()
    // every:间隔时间 on:在哪个线程 in:在哪个Runloop
    let subscription = Timer.publish(every: 1, on: .main, in: .default)
        .autoconnect()
        .sink { _ in
            print("Hello")
    }
    
    // 可以取消
    // subscription.cancel()
    
    • connect()
    // every:间隔时间 on:在哪个线程 in:在哪个Runloop
    let timerPublisher = Timer.publish(every: 1, on: .main, in: .default)
        
    let cancellablePublisher = timerPublisher
        .sink { _ in
            print("Hello")
    }
    
    let subscription = timerPublisher.connect()
    
    // 可以取消
    // subscription.cancel()
    

    Notification Publisher

    和 Timer 类似,Foundation 中的 NotificationCenter 也提供了创建 Publisher 的辅助 API。

    • 系统通知
    let subscription = NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)
        .sink(receiveValue: { _ in
            print("App进入后台")
        })
    
    • 自定义通知
    // 自定义通知名
    extension Notification.Name{
        static var myNotiName:Notification.Name {
            return Notification.Name("YungFan")
        }
    }
    // 订阅通知
    let subscription = NotificationCenter.default.publisher(for: .myNotiName)
        .sink(receiveValue: { notification in
            print(notification.object as? String)
        })
    
    // 创建通知
    let noti = Notification(name: .myNotiName, object: "some info", userInfo: nil)
    // 发送通知
    NotificationCenter.default.post(noti)
    
    • SwiftUI 监听 App 进入后台和重返前台。
    struct ContentView : View {
        
        var body: some View {
            Text("")
                // onReceive捕获通知
                .onReceive(NotificationCenter.default.publisher(for: 
                    UIApplication.willResignActiveNotification)) { _ in
                    print("App进入后台")
            }.onReceive(NotificationCenter.default.publisher(for: 
                UIApplication.willEnterForegroundNotification)) { _ in
                    print("App进入前台")
            }.onAppear() {
                    print("第一次显示")
            }
        }
    }
    

    KVO

    任何 NSObject 对象一旦被KVO监听,则可以成为一个 Publisher。

    class Person: NSObject {
        @objc dynamic var age: Int = 0
    }
    
    let person = Person()
    
    let _ = person.publisher(for: \.age)
        .sink { newValue in
            print("person的age改成了\(newValue)")
        }
    
    person.age = 10 // 改变时会收到通知
    

    @Published

    可以将任何一个属性转换成 Publisher,广泛应用于 UIKit 与 SwiftUI 中,此部分内容请参考《SwiftUI 实用教程》。

    class Student {
        
        @Published var name: String = "zhangsan"
    }
    
    let stu = Student()
    
    // 访问的时候要带上$
    let subscription = stu.$name.sink {
        print($0)
    }
    
    stu.name = "lisi"
    
    /*输出
     zhangsan
     lisi
     */
    

    相关文章

      网友评论

        本文标题:Combine-Foundation中的Publisher

        本文链接:https://www.haomeiwen.com/subject/jrrjyhtx.html