Skip to content

Instantly share code, notes, and snippets.

@woodycatliu
Last active August 29, 2022 08:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save woodycatliu/08fef8ba85fbe166ae10119269c9e13c to your computer and use it in GitHub Desktop.
Save woodycatliu/08fef8ba85fbe166ae10119269c9e13c to your computer and use it in GitHub Desktop.
Combine Publishers Zip
//
// ViewController.swift
// CombineCombine
//
// Created by Woody Liu on 2021/8/16.
//
import UIKit
import Combine
class ViewController: UIViewController {
var anyCancellables = Set<AnyCancellable>()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
mergeMany()
zipSuccess()
zipFail()
zipInZip()
}
}
extension ViewController {
fileprivate func mergeMany() {
// MARK: MergeMany 處理不同型別
Publishers.MergeMany(Task.fetchInt(int: 5), Task.fetchString(string: "ABC"), Task.fetchPotin(point: .init(x: 0, y: 1)))
.eraseToAnyPublisher()
.collect(3)
.sink { arr in
print(arr)
arr.forEach {
if let int = $0 as? Int {
print(int)
}
if let string = $0 as? String {
print(string)
}
if let point = $0 as? CGPoint {
print(point)
}
}
}.store(in: &anyCancellables)
}
fileprivate func zipSuccess() {
// MARK: zIP 3 成功
Publishers.Zip3(Task.fetchInt(int: 10), Task.fetchString(string: "BCD"), Task.fetchPotin(point: .init(x: 1, y: 1)))
.tryMap { value -> (Int, String, CGPoint) in
if let int = value.0 as? Int,
let string = value.1 as? String,
let point = value.2 as? CGPoint {
return (int, string, point)
}else {
throw CombinError.convertFail
}
}.sink(receiveCompletion: {
switch $0 {
case .failure(let error):
print(error)
default:
break
}
}, receiveValue: {
print($0)
}).store(in: &anyCancellables)
}
fileprivate func zipFail() {
// MARK Zip3 失敗版
Publishers.Zip3(Task.fetchInt(int: 11), Task.fetchString(string: "BCDF"), Task.fetchPotin(point: .init(x: 1, y: 5)))
.tryMap { value -> (Int, String, CGFloat) in
if let int = value.0 as? Int,
let string = value.1 as? String,
let point = value.2 as? CGFloat {
return (int, string, point)
}else {
throw CombinError.convertFail
}
}.sink(receiveCompletion: {
switch $0 {
case .failure(let error):
print(error)
default:
break
}
}, receiveValue: {
print($0)
}).store(in: &anyCancellables)
}
fileprivate func zipInZip() {
// MARK: 巢狀Zip
Publishers.Zip(createZip(), createZip())
.tryMap { tuple-> [(Int, String, CGPoint)] in
var arr = Array<(Int, String, CGPoint)>()
if let value = tuple.0 as? (Int, String, CGPoint) {
arr.append(value)
}
if let value = tuple.1 as? (Int, String, CGPoint) {
arr.append(value)
}
return arr
}.sink(receiveCompletion: {
switch $0 {
case .failure(let error):
print(error)
default:
break
}
}, receiveValue: {
print($0)
})
.store(in: &anyCancellables)
}
//
private func createZip()-> AnyPublisher<Any, CombinError> {
return Publishers.Zip3(Task.fetchInt(int: 11), Task.fetchString(string: "BCDF"), Task.fetchPotin(point: .init(x: 1, y: 5)))
.tryMap { value -> (Int, String, CGPoint) in
if let int = value.0 as? Int,
let string = value.1 as? String,
let point = value.2 as? CGPoint {
return (int, string, point)
}else {
throw CombinError.convertFail
}
}
.mapError( { if let error = $0 as? CombinError {
return error
}
return CombinError.convertFail
})
.eraseToAnyPublisher()
}
}
enum CombinError: Error {
case convertFail
}
class Task {
static let int = PassthroughSubject<Any, Never>()
static let string = PassthroughSubject<Any, Never>()
static let point = PassthroughSubject<Any, Never>()
static func fetchInt(int: Int)-> Future<Any, Never> {
// static func fetchInt(int: Int)-> PassthroughSubject<Any, Never> {
return Future<Any, Never> { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
print("Int is promise", Date())
promise(.success(int))
// Task.int.send(int)
}
DispatchQueue.global().asyncAfter(deadline: .now() + 7) {
print("Int is promise", Date())
promise(.success(int))
// Task.int.send(int + 1)
}
}
// return Task.int
}
static func fetchString(string: String)-> Future<Any, Never> {
// static func fetchString(string: String)-> PassthroughSubject<Any, Never> {
return Future<Any, Never> { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 4) {
print("string is promise", Date())
promise(.success(string))
// Task.string.send(string)
}
DispatchQueue.global().asyncAfter(deadline: .now() + 9) {
print("string is promise", Date())
promise(.success(string))
// Task.string.send(string + "delay")
}
}
// return Task.string
}
static func fetchPotin(point: CGPoint)-> Future<Any, Never> {
// static func fetchPotin(point: CGPoint)-> PassthroughSubject<Any, Never> {
return Future<Any, Never> { promise in
DispatchQueue.global().asyncAfter(deadline: .now() + 6) {
print("point is promise", Date())
promise(.success(point))
Task.point.send(point)
}
DispatchQueue.global().asyncAfter(deadline: .now() + 10) {
print("point is promise", Date())
promise(.success(point))
var point = point
point.y = 9
// Task.point.send(point)
}
}
// return Task.point
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment