gpt4 book ai didi

ios - 从其他 Observable 获取值(value)的 Rx Observable

转载 作者:可可西里 更新时间:2023-11-01 02:02:20 25 4
gpt4 key购买 nike

我是 RxSwift 和 MVVM 的新手。

我的 viewModel 有一个名为 rx_fetchItems(for:) 的方法完成从后端获取相关内容的繁重工作,并返回 Observable<[Item]> .

我的目标是提供名为 collectionItems 的 viewModel 的可观察属性, 最后发出的元素从 rx_fetchItems(for:) 返回, 为我的 collectionView 提供数据。

Daniel T 提供了我可能会使用的解决方案:

protocol ServerAPI {
func rx_fetchItems(for category: ItemCategory) -> Observable<[Item]>
}

struct ViewModel {

let collectionItems: Observable<[Item]>
let error: Observable<Error>

init(controlValue: Observable<Int>, api: ServerAPI) {
let serverItems = controlValue
.map { ItemCategory(rawValue: $0) }
.filter { $0 != nil }.map { $0! } // or use a `filterNil` operator if you already have one implemented.
.flatMap { api.rx_fetchItems(for: $0)
.materialize()
}
.filter { $0.isCompleted == false }
.shareReplayLatestWhileConnected()

collectionItems = serverItems.filter { $0.element != nil }.dematerialize()
error = serverItems.filter { $0.error != nil }.map { $0.error! }
}

}

这里唯一的问题是我当前的 ServerAPI aka FirebaseAPI 没有这样的协议(protocol)方法,因为它是用一个单一的方法设计的,可以像这样触发所有请求:

class FirebaseAPI {

private let session: URLSession

init() {
self.session = URLSession.shared
}

/// Responsible for Making actual API requests & Handling response
/// Returns an observable object that conforms to JSONable protocol.
/// Entities that confrom to JSONable just means they can be initialized with json.
func rx_fireRequest<Entity: JSONable>(_ endpoint: FirebaseEndpoint, ofType _: Entity.Type ) -> Observable<[Entity]> {

return Observable.create { [weak self] observer in
self?.session.dataTask(with: endpoint.request, completionHandler: { (data, response, error) in

/// Parse response from request.
let parsedResponse = Parser(data: data, response: response, error: error)
.parse()

switch parsedResponse {

case .error(let error):
observer.onError(error)
return

case .success(let data):

var entities = [Entity]()

switch endpoint.method {

/// Flatten JSON strucuture to retrieve a list of entities.
/// Denoted by 'GETALL' method.
case .GETALL:

/// Key (underscored) is unique identifier for each entity, which is not needed here.
/// value is k/v pairs of entity attributes.
for (_, value) in data {
if let value = value as? [String: AnyObject], let entity = Entity(json: value) {
entities.append(entity)
}
}

// Need to force downcast for generic type inference.
observer.onNext(entities as! [Entity])
observer.onCompleted()

/// All other methods return JSON that can be used to initialize JSONable entities
default:
if let entity = Entity(json: data) {
observer.onNext([entity] as! [Entity])
observer.onCompleted()
} else {
observer.onError(NetworkError.initializationFailure)
}
}
}
}).resume()
return Disposables.create()
}
}
}

关于rx_fireRequest最重要的事情方法是它接受一个 FirebaseEndpoint .

/// Conforms to Endpoint protocol in extension, so one of these enum members will be the input for FirebaseAPI's `fireRequest` method.

enum FirebaseEndpoint {

case saveUser(data: [String: AnyObject])
case fetchUser(id: String)
case removeUser(id: String)

case saveItem(data: [String: AnyObject])
case fetchItem(id: String)
case fetchItems
case removeItem(id: String)

case saveMessage(data: [String: AnyObject])
case fetchMessages(chatroomId: String)
case removeMessage(id: String)

}

为了使用 Daniel T 的解决方案,我必须将每个枚举大小写从 FirebaseEndpoint 转换为进入内部方法 FirebaseAPI .在每个方法中,调用 rx_fireRequest ... 如果我是正确的。

如果它有助于更​​好的服务器 API 设计,我很想做出这种改变。所以简单的问题是,这种重构是否会改进我的整体 API 设计以及它与 ViewModels 的交互方式。我意识到这现在正在演变成代码审查。

还有...这是该协议(protocol)方法及其助手的实现:

 func rx_fetchItems(for category: ItemCategory) -> Observable<[Item]>  {
// fetched items returns all items in database as Observable<[Item]>
let fetchedItems = client.rx_fireRequest(.fetchItems, ofType: Item.self)
switch category {
case .Local:
let localItems = fetchedItems
.flatMapLatest { [weak self] (itemList) -> Observable<[Item]> in
return self!.rx_localItems(items: itemList)
}

return localItems

// TODO: Handle other cases like RecentlyAdded, Trending, etc..
}
}

// Helper method to filter items for only local items nearby user.
private func rx_localItems(items: [Item]) -> Observable<[Item]> {
return Observable.create { observable in
observable.onNext(items.filter { $0.location == "LA" })
observable.onCompleted()
return Disposables.create()
}
}

如果我的 MVVM 或 RxSwift 或 API 设计方法有误,请批评指正。

最佳答案

我知道开始理解 RxSwift 很困难

我喜欢使用 SubjectVariable 作为 ViewModelObservable 的输入或 Driver 作为 ViewModel

的输出

这样您就可以将 ViewController 上发生的操作绑定(bind)到 ViewModel,在那里处理逻辑,并更新输出

这是重构代码的示例

查看模型

// Inputs
let didSelectItemCategory: PublishSubject<ItemCategory> = .init()

// Outputs
let items: Observable<[Item]>

init() {
let client = FirebaseAPI()

let fetchedItems = client.rx_fireRequest(.fetchItems, ofType: Item.self)

self.items = didSelectItemCategory
.withLatestFrom(fetchedItems, resultSelector: { itemCategory, fetchedItems in
switch itemCategory {
case .Local:
return fetchedItems.filter { $0.location == "Los Angeles" }
default: return []
}
})
}

View Controller

segmentedControl.rx.value
.map(ItemCategory.init(rawValue:))
.startWith(.Local)
.bind(to: viewModel.didSelectItemCategory)
.disposed(by: disposeBag)

viewModel.items
.subscribe(onNext: { items in
// Do something
})
.disposed(by: disposeBag)

关于ios - 从其他 Observable 获取值(value)的 Rx Observable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45465688/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com