【问题标题】:Can't pass the RxSwift PublishRelay value from custom view无法从自定义视图传递 RxSwift PublishRelay 值
【发布时间】:2021-11-01 20:55:15
【问题描述】:

我正在尝试使用 rx 操作扩展我的 KeyboardView 视图,但没有成功。根据带有断点的调试,值被传递给中继,但尽管在视图控制器中进一步订阅,但未调用扩展。可能是什么问题以及如何解决?

final class KeyboardView: UIView {

    private let disposeBag = DisposeBag()
    
    fileprivate let buttonTappedRelay = PublishRelay<ActionType>()
    
    private let digitButtons: [KeyboardButton] = {
        return stride(from: 0, through: 9, by: 1)
            .compactMap { $0 }
            .map { KeyboardButton(actionType: .digit($0)) }
    }()
    
    private let eraseButton: KeyboardButton = {
        let button = KeyboardButton(actionType: .erase)
        return button
    }()
    
    public override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupViews()
        setupConstraints()
        setupActions()
    }
    
    private func setupViews() { ... }
    
    private func setupConstraints() { ... }
    
    private func setupActions() {
        eraseButton.rx.buttonTap
            .asObservable()
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] actionType in
                self?.buttonTappedRelay.accept(actionType)
            }).disposed(by: self.disposeBag)
        
        for button in digitButtons {
            button.rx.buttonTap
                .asObservable()
                .observeOn(MainScheduler.instance)
                .subscribe(onNext: { [weak self] actionType in
                    self?.buttonTappedRelay.accept(actionType)
                }).disposed(by: self.disposeBag)
        }
    }
    
}

extension Reactive where Base: KeyboardView {
    
    internal var buttonTap: ControlEvent<ActionType> {
        return ControlEvent<ActionType>(events: base.buttonTappedRelay.asObservable() )
    }
    
}

【问题讨论】:

  • 您发布的代码中没有任何内容表明存在问题。尝试将debug 消息放入链中,看看是否可以追踪事件停止传播的位置...
  • @DanielT.,我放了断点,发现 self?.buttonTappedRelay.accept(actionType) 被成功调用,同时 ControlEvent(events: base.buttonTappedRelay.asObservable() ) 不是。虽然我在 VC 的更多代码中订阅了 buttonTap。
  • 如果一个函数没有被调用,你就不能得到它的输出。您没有调用该函数。
  • @DanielT.,您能否解释一下为什么不调用它。我通过接受函数将值发送到继电器。然后我订阅了带有继电器的 Rx 扩展。我还应该在哪里称呼它?
  • 这是一个基本的编程问题。为了使用函数的结果,您必须调用该函数。如果您认为您正在调用该函数,请显示发生这种情况的代码。

标签: uikit rx-swift rx-cocoa


【解决方案1】:

您的问题可能出在您未显示的代码中。请注意,以下代码可以编译、运行和工作:

final class KeyboardView: UIView {

    private let disposeBag = DisposeBag()

    fileprivate let buttonTappedRelay = PublishRelay<ActionType>()

    private let digitButtons: [KeyboardButton] = {
        return stride(from: 0, through: 9, by: 1)
            .compactMap { $0 }
            .map { KeyboardButton(actionType: .digit($0)) }
    }()

    private let eraseButton: KeyboardButton = {
        let button = KeyboardButton(actionType: .erase)
        return button
    }()

    public override init(frame: CGRect) {
        super.init(frame: frame)

        setupViews()
        setupActions()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupViews() {
        let stack = UIStackView(frame: bounds)
        stack.distribution = .equalSpacing
        stack.addArrangedSubview(eraseButton)
        for each in digitButtons {
            stack.addArrangedSubview(each)
        }
        addSubview(stack)
    }

    private func setupActions() {
        eraseButton.rx.buttonTap
            .asObservable()
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: { [weak self] actionType in
                self?.buttonTappedRelay.accept(actionType)
            }).disposed(by: self.disposeBag)

        for button in digitButtons {
            button.rx.buttonTap
                .asObservable()
                .observeOn(MainScheduler.instance)
                .subscribe(onNext: { [weak self] actionType in
                    self?.buttonTappedRelay.accept(actionType)
                }).disposed(by: self.disposeBag)
        }
    }

}

final class ViewController: UIViewController {
    weak var keyboard: KeyboardView?

    override func loadView() {
        super.loadView()
        let keyboard = KeyboardView(frame: view.bounds)
        view.addSubview(keyboard)
        self.keyboard = keyboard
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        keyboard!.rx.buttonTap
            .debug("?")
            .subscribe()
    }
}

extension Reactive where Base: KeyboardView {

    internal var buttonTap: ControlEvent<ActionType> {
        return ControlEvent<ActionType>(events: base.buttonTappedRelay.asObservable() )
    }
}

enum ActionType {
    case digit(Int)
    case erase
}

class KeyboardButton: UIButton {
    let actionType: ActionType
    init(actionType: ActionType) {
        self.actionType = actionType
        super.init(frame: CGRect.zero)
        backgroundColor = .red
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension Reactive where Base: KeyboardButton {
    var buttonTap: Observable<ActionType> {
        base.rx.tap.map { base.actionType }
    }
}

【讨论】:

  • 衷心感谢您对我的问题的关注。你是对的——问题在于进一步的代码——特别是过于复杂的视图模型。我修好了它,一切都按我的预期开始了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-17
  • 1970-01-01
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 1970-01-01
相关资源
最近更新 更多