我读过一些帖子说处理 RxSwift 的最佳实践是只将致命错误传递给 onError 并将结果传递给 onNext。
这对我来说很有意义,直到我意识到我无法再处理重试,因为它只发生在 onError 上。
我该如何处理这个问题?
另一个问题是,如何同时处理全局和本地重试混合?
例如,iOS 收据验证流程。
1、尝试在本地取收据
2、如果失败,请向苹果服务器索取最新的收据。
3,将收据发送到我们的后端进行验证。
4、如果成功,则整个流程完成
5、如果失败,检查错误代码是否可重试,然后返回1。
而在新的 1 中,它将强制要求从苹果服务器获取新收据。然后当它再次达到 5 时,整个流程将停止,因为这已经是第二次尝试了。意思是只重试一次。
因此,在这个例子中,如果使用状态机,并且不使用RX,我会最终使用状态机和共享一些全局状态一样isSecondAttempt: Bool
,shouldForceFetchReceipt: Bool
等等。
我如何在 rx 中设计这个流程?与这些在流程中设计的全局共享状态。
我有一个名为User
符合Codable
Swift4 中引入的对象。
例如,这个对象曾经是
struct User: Codable {
var firstName: String
}
Run Code Online (Sandbox Code Playgroud)
我们使用PropertyListDecoder().decode(User.self, from: data)
和PropertyListEncoder().encode(value)
将其编码User
为Data
并解码Data
为User
。
现在我们将对象更新为
struct User: Codable {
var firstName: String
var isLoggedIn: Bool
}
Run Code Online (Sandbox Code Playgroud)
如果我们的应用程序从旧应用程序更新,旧应用程序Data
存储在UserDefault
. 更新后应用程序要做的第一件事就是获取它Data
并尝试User
使用PropertyListDecoder().decode(User.self, from: data)
. 但是,它给出了一个错误:
po PropertyListDecoder().decode(User.self, from: data)
? DecodingError
? keyNotFound : 2 elements
- .0 : CodingKeys(stringValue: "isLoggedIn", intValue: nil)
? .1 : Context
- …
Run Code Online (Sandbox Code Playgroud) 在我的程序中,它使用两者
DispatchQueue.global(qos: .background)
Run Code Online (Sandbox Code Playgroud)
和
self.concurrentQueue.sync(flags: .barrier)
Run Code Online (Sandbox Code Playgroud)
处理后台多线程问题.
它是迅速3所以我使用最新的方式来获取childContext:
lazy var context: NSManagedObjectContext = {
return (UIApplication.shared.delegate as! AppDelegate).persistentContainer.newBackgroundContext()
}()
Run Code Online (Sandbox Code Playgroud)
我也启用-com.apple.CoreData.ConcurrencyDebug 1
了调试
然后出现问题:
1,当有API调用并且在回调块(后台线程)中时,我需要获取核心数据,编辑,然后保存.我尝试使用上面代码中的self.context来调用performBlockAndWait
并执行save
此块内部.整个过程很顺利但是当我尝试在此块之外但在回调块内部访问我的结果时,会发生错误.我也尝试getObjectById
通过self.context和self.context.parent 获取objectId,并且此行发生错误.我做错了什么,我应该怎么做?因为我需要在许多不同的线程(不是上下文)中的任何地方使用结果.
2,我读了一篇文章说每个线程需要一个上下文,那么在我的情况下,如果它是从API调用回调的话我如何确定它是哪个确切的线程?我真的需要这样做吗?
3,你可能会问为什么我需要一个privateConcurrentType,因为我的程序需要在后台线程中运行,所以它必须这样做,(从其他帖子中读取),这是对的吗?
4,即使在我的问题1中,通过将objectId传递给不同的Context来获取对象仍然不能在我的情况下工作.我们假设这是正确的方法.我怎么能管理在整个程序中在不同的线程中传递这么多的objectID而不是超级凌乱?对我来说这听起来很疯狂,但我想有一个更清洁,更简单的方法来解决这个问题.
5,我已经看了很多帖子都是一些很老的(前迅疾3),他们所要做的childContext.save
,然后parentContext.save
,但因为我使用上面的代码(SWIFT 3只).似乎我可以做childContext.save只是为了让它工作?我对吗?
我一直在尝试对retryWhen
运算符进行测试RxSwift
,但遇到了Reentrancy Anomaly
问题,代码如下:
Observable<Int>.create { observer in\n observer.onNext(1)\n observer.onNext(2)\n observer.onNext(3)\n observer.onNext(4)\n observer.onError(RequestError.dataError)\n return Disposables.create()\n }\n .retryWhen { error in\n return error.enumerated().flatMap { (index, error) -> Observable<Int> in\n let maxRetry = 1\n print("index: \\(index)")\n return index < maxRetry ? Observable.timer(1, scheduler: MainScheduler.instance) : Observable.error(RequestError.tooMany)\n }\n }\n .subscribe(onNext: { value in\n print("This: \\(value)")\n }, onError: { error in\n print("ERRRRRRR: \\(error)")\n })\n .disposed(by: disposeBag)\n
Run Code Online (Sandbox Code Playgroud)\n\n通过上面的代码,它给出:
\n\nThis: 1\nThis: 2\nThis: 3\nThis: 4\nindex: 0\nThis: 1\nThis: 2\nThis: 3\nThis: 4\nindex: …
Run Code Online (Sandbox Code Playgroud) let jsonString = """
{
"name":1,
"gender":"male",
}
"""
struct Person: Codable {
var name: String
var gender: String
public init(from decoder: Decoder) throws {
do {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
gender = try container.decode(String.self, forKey: .gender)
} catch {
print("XXXXXX \(error)")
}
}
}
Run Code Online (Sandbox Code Playgroud)
从上面的代码,它不会编译,因为它抱怨,
从初始化程序返回而不初始化所有存储的属性.
我想抛出一些错误,但如果没有,我该怎么办呢
我的观点是在某些地方我们知道变量根本不会有 nil 但由于某种原因我们不能在类的 init 函数中实例化它所以我们必须使它成为可选的。
我也知道我们可以使用可选的绑定或保护技术来轻松摆脱它。
但是在我看来,让应用程序因为隐式解包/强制解包而在一些非常愚蠢的错误中崩溃对于开发阶段的开发人员来说是有益的。
我的例子是:
class TopStoriesViewModelTests: XCTestCase {
var viewModel: TopStoriesViewModel!
override func setUp() {
super.setUp()
viewModel = TopStoriesViewModel(interactor: MockTopStoriesInteractor())
}
func testArticleDidVisited() {
viewModel.visited = xxxxxx
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我可以制作TopStoriesViewModel
一个?
then 保护它,或者在每个测试用例中都使用它,但我觉得没有必要。我知道我也可以使用viewModel?.xxx
。但这不是重点。
我的问题是,在某些情况下,例如我给出的示例,强制解包/隐式解包是有益的,我是否正确。