在所有成员初始化之前由闭包捕获的 Swift5(+RxSwift) 'self'
Posted
技术标签:
【中文标题】在所有成员初始化之前由闭包捕获的 Swift5(+RxSwift) \'self\'【英文标题】:Swift5(+RxSwift) 'self' captured by a closure before all members were initialized在所有成员初始化之前由闭包捕获的 Swift5(+RxSwift) 'self' 【发布时间】:2019-05-08 11:27:01 【问题描述】:我正在学习 MVVM + RxSwift。 我想保存一个值以在下一个流程中重用它。 但是我遇到了上面的错误。
我假设我初始化了“translatedText”的值,但错误仍然出现。
我已经尝试了一些方法来初始化声明等等......
import UIKit
import RxSwift
final class ViewModel
private let api: apiProtocol
let validationText: Observable<String>
let getObservable: Observable<String>
var translatedText: String
// var translatedText: String = "" //this case also dosn't work
init(inputObservable: Observable<String?>, changeButtonClicked: Observable<Void>, model: ModelProtocol, api: apiProtocol = APICntl())
self.api = api
self.translatedText = "" //I guess I initialised this here
let event = inputObservable
.flatMap input -> Observable<Event<Void>> in
if let text = input
self.translatedText = text // error. i want to save "input" to use at "let tapEvent"
return model
.validate(text: input)
.materialize()
.share()
self.validationText = event
.flatMap event -> Observable<String> in
switch event
case .next:
return .just("")
case let .error(error as ModelError):
return .just(error.errorLabel)
case .error, .completed:
return .empty()
.startWith(ModelError.invalidBlank.errorLabel)
let tapEvent = changeButtonClicked
.flatMap (result) -> Observable<Event<String>> in
return api
.fetch(text: self.translatedText) // I want use it here
.materialize()
.share()
self.getObservable = tapEvent
.flatMap event -> Observable<String> in
switch event
case .next:
return .just(event.element!)
case let .error(error as ModelError):
return .just(error.errorLabel)
case .error, .completed:
return .empty()
你们有更好的解决方案吗?
-----自行解决-----
我只是在 let 事件之前创建了一个临时变量,它可以按我的意愿工作。
final class ViewModel
private let api: apiProtocol
let validationText: Observable<String>
let getObservable: Observable<String>
init(inputObservable: Observable<String?>, changeButtonClicked: Observable<Void>, model: ModelProtocol, api: apiProtocol = APICntl())
self.api = api
var temp = ""
let event = inputObservable
.flatMap input -> Observable<Event<Void>> in
if let text = input
temp = text
return model
.validate(text: input)
.materialize()
.share()
【问题讨论】:
【参考方案1】:您不应该使用一些随机的“临时”内存块将两个独立的可观察流相互联系起来。这两个流依赖于inputObservable
,这应该说清楚。此外,您的视图模型可以大大简化...
final class ViewModel
let validationText: Observable<String>
let getObservable: Observable<String>
init(inputObservable: Observable<String?>, changeButtonClicked: Observable<Void>, model: ModelProtocol, api: apiProtocol = APICntl())
let translatedText = inputObservable.share() // this line is unnecessary if `inputObservable` is already hot.
self.validationText = translatedText
.flatMap input in
return model
.validate(text: input)
.map ""
.catchError error in .just((error as? ModelError)?.errorLabel ?? error.localizedDescription)
.startWith(ModelError.invalidBlank.errorLabel)
self.getObservable = changeButtonClicked
.withLatestFrom(translatedText)
.compactMap $0
.flatMap translatedText in
return api
.fetch(text: translatedText)
.catchError error in .just((error as? ModelError)?.errorLabel ?? error.localizedDescription)
【讨论】:
【参考方案2】:您的问题是,当您调用 flatMap
时,self
没有完全初始化。在您的情况下,validationText
和 getObservable
处于未定义状态。
最快的方法是使它们隐式解包,但您确实必须保证在初始化之前它们不会被访问:
final class ViewModel
private let api: apiProtocol
let validationText: Observable<String>!
let getObservable: Observable<String>!
var translatedText: String!
// ...
【讨论】:
感谢您的评论。这两个由self.validationText = event
和self.getObservable = tapEvent
初始化,所以问题是self
在初始化之前在闭包中用作self.translatedText
。但我可以通过简单地执行上面的代码来解决它。我找到了另一种使用lazy
的方法,但这次不是。
如果您希望您的应用程序无崩溃,则应避免这样做。【参考方案3】:
---- 自行解决-----
我只是在 let 事件之前创建了一个临时变量,它可以按我的意愿工作。
final class ViewModel
private let api: apiProtocol
let validationText: Observable<String>
let getObservable: Observable<String>
init(inputObservable: Observable<String?>, changeButtonClicked: Observable<Void>, model: ModelProtocol, api: apiProtocol = APICntl())
self.api = api
var temp = ""
let event = inputObservable
.flatMap input -> Observable<Event<Void>> in
if let text = input
temp = text
return model
.validate(text: input)
.materialize()
.share()
【讨论】:
以上是关于在所有成员初始化之前由闭包捕获的 Swift5(+RxSwift) 'self'的主要内容,如果未能解决你的问题,请参考以下文章