美文网首页
Combine(二) Operators

Combine(二) Operators

作者: Joshua666 | 来源:发表于2019-10-22 15:40 被阅读0次

    Combine有很多方便的方法: Operators。这些operators可以把从publisher传出来的values一层一层的过滤/筛选/变型,subscriber就可以拿到自己真正需要的values了。

    1、collect()

    collect就是把一个一个输出的value全都放在array里,然后等publisher结束后,输出这个array:

    ["A", "B", "C", "D", "E"].publisher
      .collect()
      .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    // ["A", "B", "C", "D", "E"]
    // finished
    

    通常我们会限制collect需要收集values的个数,不然无限等着可能浪费内存:

    .collect(2)
    
    // ["A", "B"]
    // ["C", "D"]
    // ["E"]
    // finished
    

    2、map()

    这和swift中的用法一样

    ["A", "B", "C"].publisher
        .map { $0 + $0 }
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    AA
    BB
    CC
    finished
    

    3、map key path

    如果输出的value有多个属性,那么也可以用map和keypath来拆分:

    [(x: 2, y: 3), (x: 1, y: 5), (x: 2, y: 6)].publisher
        .map(\.x, \.y)
        .sink(receiveCompletion: { print($0) },
            receiveValue: { x, y in print(x + y) })
        .store(in: &subscriptions)
    
    5
    6
    8
    finished
    

    4、tryMap

    tryMap就是map的closure里有可能throw,throw的话就筛选掉这个value:

    Just("/fake")
        .tryMap { try FileManager.default.contentsOfDirectory(atPath: $0) }
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    No such file or directory
    

    5、flatMap

    如果你有一个publisher发送的value的某些属性也是publisher, 那sink只会receive外面这个publisher发出的value,属性publisher发出的value要是也想接收,那你就可以用flatMap

    struct Person {
        let name : String
        var age: CurrentValueSubject<Int, Never>
        
        init(name: String, age: Int) {
            self.name = name
            self.age = CurrentValueSubject(age)
        }
    }
    
    var me = Person(name: "Joshua", age: 18)
    var you = Person(name: "Dog", age: 28)
    
    let people = PassthroughSubject<Person, Never>()
    people
        .flatMap{ $0.age }
        .sink(receiveCompletion: { _ in
            print("people completed")
        }, receiveValue: { val in
            print(val)
        })
    
    people.send(me)
    people.send(you)
    me.age.value = 19
    you.age.value = 30
    
    //输出
    18
    28
    19
    30
    

    好好看一下这个例子,我觉得大家应该就都理解了吧,这属于比较复杂的一个operator了。flatMap还可以限制订阅publisher的个数:

    var me = Person(name: "Joshua", age: 18)
    var you = Person(name: "Dog", age: 28)
    var she = Person(name: "SHE", age: 16)
    
    let people = PassthroughSubject<Person, Never>()
    people
        .flatMap(maxPublishers: .max(2)) { $0.age }
        .sink(receiveCompletion: { _ in
            print("people completed")
        }, receiveValue: { val in
            print(val)
        })
    
    people.send(me)
    people.send(you)
    people.send(she)
    me.age.value = 19
    you.age.value = 30
    she.age.value = 17
    
    // 输出和之前那个一样
    

    6、replaceNil(with:)

    "人"如其名的这种我就不解释了

    ["A", nil, "C"].publisher
    .replaceNil(with: "null")
    .map { $0! }
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)
    
    A
    null
    C
    finished
    

    7、replaceEmpty(with:)

    let empty = Empty<String, Never>()
    empty
    .replaceEmpty(with: "Empty")
    .sink(receiveCompletion: { print($0) },
        receiveValue: { print($0) })
    .store(in: &subscriptions)
    
    Empty
    finished
    

    这个Empty一般就是用来测试或demo,直接发送.finish

    8、reduce(0)

    这个和之前文章中介绍的reduce一样。publisher一定要结束才会输出最后值

    [1, 2, 3].publisher
        .reduce(0, +)
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    6
    finished
    

    9、scan

    scan和reduce差不多,但是scan不是最后才输出值,每个都会输出

    [1, 2, 3].publisher
        .scan(0, +)
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    1
    3
    6
    finished
    

    10、filter

    [1, 2, 3].publisher
        .filter { $0 < 2 }
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    1
    finished
    

    11、removeDuplicates()

    注意这个并不是所有重复的都去掉,只是publisher当前要发出的value和上个发出的一样的才会去掉。要让系统排重,那value一定是Equatable, 不然你就得自定义相等的条件:

    [1, 1, 2].publisher
        .removeDuplicates()
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    1
    2
    finished
    

    12、compactMap

    跟swift中的一样,会删掉invalid的值

    ["1", "a", "2"].publisher
        .compactMap { $0 }
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    1
    2
    finished
    

    13、ignoreOutput()
    只想知道publisher是不是结束了,不care他发出了什么value

    14、first() 和 first(where:)

    接收到第一个值就取消订阅,可以用where加条件

    [1, 2, 3].publisher
        .first { $0 > 1 }
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    2
    finished
    

    15、last()和last(where:)

    跟上一个一样,唯一区别是publisher必须结束才会输出,原因不用说了吧

    16、dropFirst()

    .dropFirst(3)就是不要前3个

    17、drop(while:)

    直到while的条件符合,都不要!但一旦符合条件了,后面的都要!

    [1, 2, 3, 4, 5].publisher
        .drop(while: { $0 < 3 })
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    3
    4
    5
    finished
    

    18、drop(untilOutputFrom:)

    这个其实也很简单理解,就是你有两个publisher,用这个operator的publisher必须要等另一个publisher输出才会输出,之前的都不要了

    19、prefix()、prefix(while:)、prefix(untilOutputFrom:)

    跟drop的三个正好相反,保留前几个values直到....唯一要注意的是,跟first一样,符合条件之后就cancel

    20、prepend()

    在publisher输出之前先输出prepend里面的同类型values

    [1, 2, 3].publisher
        .prepend(9, 8) // 也可以prepend([9, 8]),结果一样
        .sink(receiveCompletion: { print($0) },
            receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    9
    8
    1
    2
    3
    finished
    

    还可以prepend(另一个publisher),这样只有prepend的publisher完成输出,本来的publisher才开始输出

    21、append()

    嗯没错,跟之前相反,但你要注意,只有publisher结束了,才会输出append的values

    现写到这儿...还有一半...shit...

    相关文章

      网友评论

          本文标题:Combine(二) Operators

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