【问题标题】:How to replace protocol with DelegateProxy from RxSwift?如何用 RxSwift 中的 DelegateProxy 替换协议?
【发布时间】:2018-02-09 19:24:54
【问题描述】:

我开始意识到使用RxSwift 的好处并尝试将其合并到我的代码中,但我不确定我是否理解DelegateProxy 的用法。

目前在我的代码中,我有以下内容:

struct SampleModel: Decodable
{
    var first_name: String
    var last_name: String

    init(first_name: String, last_name: String)
    {
        self.first_name = first_name
        self.last_name = last_name
    }
}

class ViewModel
{
    var model: SampleModel

    public var fullName: String {
        return model.first_name + model.last_name
    }

    init(model: SampleModel)
    {
        self.model = model
    }
}

我正在使用这样的协议和委托:

protocol NetworkDelegate
{
    func dataReceived(data: [Decodable]?, error: Error?)
}

class Network: NSObject
{
    var databaseLink = String()

    var networkDelegate: NetworkDelegate!

    init(databaseLink: String)
    {
        super.init()

        self.databaseLink = databaseLink
    }

    func getDatabaseData<T: Decodable>(model: T.Type)
    {
        guard let url = URL(string: databaseURL) else {
            return
        }

        request(url).responseJSON { (json) in
            switch json.result
            {
                case .success:
                    guard let data = json.data else {
                        return
                    }

                    do
                    {
                        let models = try JSONDecoder().decode([T].self,
                                                              from: data)

                        self.networkDelegate.dataReceived(data: models,
                                                          error: nil)
                    }
                    catch let jsonErr
                    {
                        print(jsonErr)
                    }

                case .failure(let error):
                    self.networkDelegate.dataReceived(data: nil,
                                                      error: error)
            }
        }
    }
}

extension ViewController: NetworkDelegate
{
    func dataReceived(data: [Decodable]?, error: Error?)
    {
        guard let models = data else {
            return
        }

        for model in models
        {
            guard let myModel = model as? SampleModel else {
                return
            }

            viewModels.append( ViewModel(model: myModel) )
        }
    }
}

var viewModels = [ViewModel]()
weak var networkDelegate: NetworkDelegate?

override func viewDidLoad()
{
    super.viewDidLoad()

    let network = Network(databaseLink: "some url")
    network.networkDelegate = self
    network.getDatabaseData(model: SampleModel.self)
}

在研究这个话题RxSwift时,我发现了以下内容:

  1. Is this the best way to convert Swift protocol to RxDelegateProxy?
  2. Cannot receive event with custom DelegateProxy and Protocol

以此为参考,我创建了一些框架代码:

import RxSwift
import RxCocoa

protocol NetworkDelegate: class
{
    func dataReceived(data: [Decodable]?, error: Error?)
}

class NetworkDeleteProxy: DelegateProxy<ViewController, NetworkDelegate>, DelegateProxyType
{
    public static func registerKnownImplementations()
    {
        <#code#>
    }

    public static func currentDelegate(for object: ViewController) -> NetworkDelegate?
    {
        return object.networkDelegate
    }

    public static func setCurrentDelegate(_ delegate: NetworkDelegate?, to object: ViewController)
    {
        <#code#>
    }
}

但是,我后来对如何实现其余功能并像原来的方式一样使用有点困惑:

let network = Network(databaseLink: "some url")
network.networkDelegate = self
network.getDatabaseData(model: SampleModel.self)

我怎样才能做到这一点?谢谢。

【问题讨论】:

  • 委托代理依赖 objc 消息调度进行拦截 github.com/ReactiveX/RxSwift/issues/1442#issuecomment-335475647

标签: ios swift rx-swift


【解决方案1】:

DelegateProxy 应该在与依赖于delegates 的 Cocoa API 集成时使用。

如果您打算采用 Rx 方式,请将所有内容都视为事件流。

让我们看看如何将您的代码转换为 observable:

func getDatabaseData<T: Decodable>() -> Observable<[T]>
{
    guard let url = URL(string: databaseURL) else {
        return .error(NetworkServiceErrors.missingDatabaseURL)
    }

    return Observable.create { observer in
        self.request(url).responseJSON { (json) in
            switch json.result {
            case .success:
                guard let data = json.data else {
                    return observer.onError(NetworkServiceErrors.noData)
                }

                do
                {
                    let models = try JSONDecoder().decode([T].self,
                                                          from: data)

                    observer.onNext(models)
                }
                catch let jsonErr
                {
                    observer.onError(NetworkServiceErrors.parsingError(jsonErr))
                }

            case .failure(let error):
                observer.onError(NetworkServiceErrors.someError(error))
            }
            observer.onCompleted()

            return Disposables.create { /* usually some code to cancel the request */ }
        }
    }
}

现在让我们使用您的网络层构建一个 ViewModel:

class MyListViewModel {
    // inputs
    let loadData: AnyObserver<Void>

    // outputs
    let myModels: Driver<[SampleModel]>

    private let network = Network(databaseLink: "some url")

    init() {
        let loadData = PublishRelay<Void>()
        self.loadData = loadData.asObserver()

        self.myModels = loadData.flatMapLatest { _ -> Driver<[SampleModel]>
            return network.getDatabaseData().asDriver(onErrorJustReturn: [])
        }
    }
}

你的视图控制器:

let viewModel = MyListViewModel()
let disposeBag = DisposeBag()

func viewDidLoad() {
    super.viewDidLoad()

    bindViewModel()
}

func viewWillAppear() {
    super.viewWillAppear()

    // trigger loading of your data
    viewModel.loadData.onNext(())
}

func bindViewModel() {
    // some button that reloads data
    button.rx.tap.subscribe(viewModel.loadData).disposed(by: disposeBag)

    // will log all events but you should actually use it to drive the content of a tableview for example
    viewModel.myModels.debug().drive().disposed(by: disposeBag)
}

这只是一个基本示例,我还没有测试过代码,但它应该让你知道你可以做什么。

您可以查看Moya(网络库)和RxMoya,了解更高级的实现或寻求灵感。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 2018-11-06
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多