组合 Cocoa UIView 自定义扩展不起作用

combine cocoa uiview custom extension does not work

提问人:안은노 提问时间:8/15/2023 更新时间:8/15/2023 访问量:51

问:

我不知道为什么我的扩展 UIView tabPublisher 不起作用。

我读了 swift combine cocoa 库。并想做 UIView 扩展。(Swift combine cocoa 没有给出 UIView 扩展。

另一个关于自定义uiview扩展的例子,使用限制使uiview扩展后。但我认为这毫无意义。

enter image description here

extension Combine.Publishers {
    struct CustomTarget<Control: AnyObject>: Publisher {
        // swiftlint: disable nesting
        typealias Output = Void
        typealias Failure = Never
        // swiftlint: enable nesting
        let control: Control
        let addTargetAction: (Control, AnyObject, Selector) -> Void
        let removeTargetAction: (Control, AnyObject, Selector) -> Void
        
        init(
            control: Control,
            addTargetAction: @escaping (Control, AnyObject, Selector) -> Void,
            removeTargetAction: @escaping (Control, AnyObject, Selector) -> Void) {
            self.control = control
            self.addTargetAction = addTargetAction
            self.removeTargetAction = removeTargetAction
        }
        
        func receive<S>(subscriber: S) where S: Subscriber, S.Failure == Failure, S.Input == Output {
            let subscription = Subscription(
                subscriber: subscriber,
                control: control,
                addTargetAction: addTargetAction,
                removeTargetAction: removeTargetAction)
            subscriber.receive(subscription: subscription)
        }
    }
}

extension Combine.Publishers.CustomTarget {
    class Subscription<S: Subscriber, Control: AnyObject>: Combine.Subscription where S.Input == Void {
        private var subscriber: S?
        weak private var control: Control?
        
        let removeTargetAction: (Control, AnyObject, Selector) -> Void
        let action = #selector(handleAction)
        
        init(
            subscriber: S,
            control: Control,
            addTargetAction: @escaping (Control, AnyObject, Selector) -> Void,
            removeTargetAction: @escaping (Control, AnyObject, Selector) -> Void) {
            self.subscriber = subscriber
            self.control = control
            self.removeTargetAction = removeTargetAction
            addTargetAction(control, self, action)
        }
        
        func request(_ demand: Subscribers.Demand) {
            
        }
        
        func cancel() {
            subscriber = nil
            removeTargetAction(control!, self, action)
        }
        
        @objc func handleAction() {
            _ = subscriber?.receive()
        }
    }
}

extension UITapGestureRecognizer {
    var tabGesturePublisher: AnyPublisher<UITapGestureRecognizer, Never> {
        gesturePublisher(for: self)
    }
}

private func gesturePublisher<Gesture: UIGestureRecognizer>(for gesture: Gesture) -> AnyPublisher<Gesture, Never> {
    Publishers.CustomTarget(
        control: gesture,
        addTargetAction: { gesture, target, action in
            gesture.addTarget(target, action: action)},
        removeTargetAction: { gesture, target, action in
            gesture.removeTarget(target, action: action)
        })
    .subscribe(on: DispatchQueue.main)
    .map { gesture }
    .eraseToAnyPublisher()
}

上述代码存在于可可组合中 https://github.com/CombineCommunity/CombineCocoa/blob/main/Sources/CombineCocoa/CombineControlTarget.swift

下面的代码是我的自定义 UIView 扩展。

extension UIView {
    var tabPublisher: AnyPublisher<UITapGestureRecognizer, Never> { // this is problem
        UITapGestureRecognizer().tabGesturePublisher
    }
}

我的代码有什么问题? 手势不起作用。

iOS Swift UIVieview 手势 组合

评论


答:

0赞 Matic Oblak 8/15/2023 #1

我相信您正在寻找的解决方案可能如下:

extension UIView {
    var tapPublisher: AnyPublisher<UITapGestureRecognizer, Never> {
        let recognizer = UITapGestureRecognizer()
        addGestureRecognizer(recognizer)
        return recognizer.tabGesturePublisher
    }
}

你在你的情况下所做的是

var tabPublisher: AnyPublisher<UITapGestureRecognizer, Never> { // this is problem
    let recognizer = UITapGestureRecognizer()
    return recognizer.tabGesturePublisher
}

您创建了一个手势识别器,但未将其与当前视图关联。它缺少.因此,手势识别器永远不会触发,并且实际上会在方法执行后立即解除分配,因为没有任何内容保留它。self.addGestureRecognizer(recognizer)

评论

0赞 안은노 8/15/2023
感谢您的回复。但是每次调用点击事件时,此代码都会附加手势和分离。哎呀?
0赞 Matic Oblak 8/16/2023
@안은노 并非每次调用 tap 事件时。但每次调用时,它都会附加一个新手势。因此,在大多数情况下,每个视图只应调用一次。tapPublisher