监听ViewWillAppear(从RxSwift迁移到Combine)
Combine实现UIViewController的viewWillAppear监听及过滤
以下是对应RxSwift实现的Combine版本,通过扩展UIViewController提供viewWillAppearPublisher,实现监听viewWillAppear事件并过滤图片查看器已展示的场景:
import Combine import UIKit private var viewWillAppearSubjectKey: UInt8 = 0 extension UIViewController { /// 监听viewWillAppear事件的Publisher,自动过滤图片查看器已展示的情况 var viewWillAppearPublisher: AnyPublisher<Void, Never> { // 为每个ViewController实例关联独立的PassthroughSubject let subject = associatedObject(forKey: &viewWillAppearSubjectKey) { PassthroughSubject<Void, Never>() } // 仅执行一次方法交换,hook viewWillAppear生命周期方法 static let swizzleViewWillAppear: Void = { let originalSelector = #selector(UIViewController.viewWillAppear(_:)) let swizzledSelector = #selector(UIViewController.swizzled_viewWillAppear(_:)) guard let originalMethod = class_getInstanceMethod(Self.self, originalSelector), let swizzledMethod = class_getInstanceMethod(Self.self, swizzledSelector) else { return } method_exchangeImplementations(originalMethod, swizzledMethod) }() _ = Self.swizzleViewWillAppear return subject .filter { [weak self] _ in // 过滤图片查看器已展示的场景 !(self?.isImageViewerPresented ?? false) } .eraseToAnyPublisher() } // 关联对象辅助方法,存储每个实例的Subject private func associatedObject<T>(forKey key: UnsafeRawPointer, initialValue: () -> T) -> T { if let existing = objc_getAssociatedObject(self, key) as? T { return existing } let newValue = initialValue() objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) return newValue } // 交换后的viewWillAppear方法,执行原逻辑后发送事件 @objc private func swizzled_viewWillAppear(_ animated: Bool) { // 调用原方法(因方法已交换,此处实际执行系统原生viewWillAppear逻辑) swizzled_viewWillAppear(animated) // 向Subject发送事件 let subject = objc_getAssociatedObject(self, &viewWillAppearSubjectKey) as? PassthroughSubject<Void, Never> subject?.send(()) } } // 需在ViewController中实现该属性,用于判断图片查看器是否展示 extension UIViewController { var isImageViewerPresented: Bool { // 替换为你的实际判断逻辑,例如检查presentedViewController是否为图片查看器类型 return presentedViewController is ImageViewerViewController } }
使用示例
在ViewController中订阅这个Publisher:
class DemoViewController: UIViewController { private var cancellables = Set<AnyCancellable>() override func viewDidLoad() { super.viewDidLoad() viewWillAppearPublisher .sink { [weak self] in // 处理viewWillAppear事件,此时图片查看器未处于展示状态 self?.refreshPageContent() } .store(in: &cancellables) } private func refreshPageContent() { // 执行你的业务逻辑 } }
实现说明
- 方法交换(Method Swizzling):Hook系统
viewWillAppear(_:)方法,在原生命周期逻辑执行后发送事件,不干扰原有流程 - 关联对象:为每个ViewController实例独立存储
PassthroughSubject,避免不同实例间的事件串扰 - 过滤逻辑:通过
filter操作符自动排除图片查看器已展示的场景,和RxSwift实现逻辑完全对齐 - 类型擦除:返回
AnyPublisher隐藏内部实现细节,符合Combine最佳实践
内容的提问来源于stack exchange,提问作者bumseok park
相关产品推荐
相关产品推荐

