59 lines
1.8 KiB
Swift
59 lines
1.8 KiB
Swift
//
|
||
// CombineExt.swift
|
||
// Crush
|
||
//
|
||
// Created by Leon on 2025/8/7.
|
||
//
|
||
|
||
import Combine
|
||
import UIKit
|
||
|
||
extension UITextField {
|
||
var textPublisher: AnyPublisher<String?, Never> {
|
||
NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: self)
|
||
.map { ($0.object as? UITextField)?.text }
|
||
.eraseToAnyPublisher()
|
||
}
|
||
}
|
||
|
||
extension UITextView {
|
||
var textPublisher: AnyPublisher<String?, Never> {
|
||
NotificationCenter.default
|
||
.publisher(for: UITextView.textDidChangeNotification, object: self)
|
||
.map { ($0.object as? UITextView)?.text }
|
||
.eraseToAnyPublisher()
|
||
}
|
||
}
|
||
|
||
extension Publishers {
|
||
/*
|
||
使用:
|
||
Publishers.eitherLatest(container.$whoIm, container.$birthdayDate)
|
||
.sink { whoIm, birthday in
|
||
// whoIm: String?
|
||
// birthday: Date?
|
||
print("更新 -> whoIm=\(whoIm ?? "nil"), birthday=\(birthday?.description ?? "nil")")
|
||
}
|
||
.store(in: &cancellables)
|
||
|
||
*/
|
||
/// 当任一上游(输出为 Optional)更新时触发,输出为两者的“最新快照”
|
||
static func eitherLatest<A, B, P1: Publisher, P2: Publisher>(
|
||
_ p1: P1,
|
||
_ p2: P2
|
||
) -> AnyPublisher<(A?, B?), Never>
|
||
where P1.Output == A?, P2.Output == B?, P1.Failure == Never, P2.Failure == Never {
|
||
|
||
let left = p1.map { value -> (A?, B?) in (value, nil as B?) }
|
||
let right = p2.map { value -> (A?, B?) in (nil as A?, value) }
|
||
|
||
return Publishers.Merge(left, right)
|
||
// 记住历史最新值:新的非 nil 覆盖对应位;nil 则沿用旧值
|
||
.scan((nil as A?, nil as B?)) { last, new in
|
||
(new.0 ?? last.0, new.1 ?? last.1)
|
||
}
|
||
.eraseToAnyPublisher()
|
||
}
|
||
}
|
||
|