如何用RxSwift中的DelegateProxy替换协议?

时间:2018-02-09 19:24:54

标签: ios swift rx-swift

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

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

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) } 时,我发现了以下内容:

  1. Is this the best way to convert Swift protocol to RxDelegateProxy?
  2. Cannot receive event with custom DelegateProxy and Protocol
  3. 使用它作为参考我创建了一些骨架代码:

    RxSwift

    然而,之后我对如何实现其余功能并使用原始方式有点困惑:

    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#>
        }
    }
    

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

1 个答案:

答案 0 :(得分:2)

在与依赖DelegateProxy的Cocoa API集成时,应该使用

delegates

如果您打算采用Rx方式,请将所有事物视为一系列事件。

让我们看看如何将代码转换为可观察的代码:

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: [])
        }
    }
}

您的ViewController:

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,以查看更高级的实施或灵感。