例如,有一个简单的任务可以进行网络调用,然后映射结果。
class Task {
func execute() -> Single<String> {
return doSomeRequest().flatMap { [weak self] data in
if let string = self?.map(data: data) {
return .just(string)
}
return .error(Error())
}
}
func doSomeRequest() -> Single<Data> {
// makes network call and returns Data
}
func map(data: Data) -> String? {
// maps Data to String
}
}
并且有使用此Task
的函数:
func fetchSomeString() {
Task().execute().subscribe(onSuccess: { string in
print(string)
}).disposed(by: disposeBag)
}
问题在于Task
在doSomeRequest()
之前获得回复之前已被取消初始化,原因是weak self
中的flatMap
。其中一个解决方案是将Task实例存储为属性,但是假设我的情况没有位置。
是否有任何解决方案不会导致flatMap
内存泄漏,但会正确执行Task
?
答案 0 :(得分:1)
是&#39;一种解决方案是将Task
实例存储为属性&#39;或者您可以在execute
函数中传递/实质上存储实例。
static func execute(_ task: Task) -> Single<String> {
return task.doSomeRequest().flatMap { data in
if let string = task.map(data: data) {
return .just(string)
}
return .error(Error())
}
}
然后称之为:
Task.execute(Task()).subscri...
答案 1 :(得分:1)
您可以将map(data:)
设为静态方法。这样您就不需要task
实例,如果map
实例没有使用任何实例成员,它可能比实例方法更有意义。
class Task {
func execute() -> Single<String> {
return doSomeRequest().map { [weak self] data in
guard let string = Task.map(data: data) else {
throw Error()
}
return string
}
}
func doSomeRequest() -> Single<Data> {
// makes network call and returns Data
}
static func map(data: Data) -> String? {
// maps Data to String
}
}
我也通过调用Single.map
并抛出错误对您进行了一些更改,这更易读。
答案 2 :(得分:1)
在我看来,您只需使用强引用self
而不是弱引用。
我假设您的闭包被评估一次然后被丢弃。如果是这种情况,那么您将在操作结束时temporarily have a strong reference cycle that will self-break。
答案 3 :(得分:1)
其中一个解决方案是将Task实例存储为属性,但是 让我们说我的情况没有地方。
有一个很棒的运算符可以将Task
实例存储为属性,并且它不需要存储它的位置。该运算符名为Using。
这是一个小例子:
flatMapLatest({ (room: String?) -> Observable<WebSocketServiceValue> in
switch room {
case .some(let room):
return Observable
.using({ WebSocketServiceInstance(room: room) }, observableFactory: { $0.observable })
case .none:
return Observable<WebSocketServiceValue>
.just(WebSocketServiceValue.connected(false))
}
})
我观察了一个可选String
的房间。如果有一个有效的房间 - 我创建一个WebSocketServiceInstance
并观察它的信号。更改房间后,WebSocketServiceInstance
因flatMapLatest
运营商而被取消。因此,只要您有连接,该实例就会存在。
在您的示例中,只要您使用Task
运算符执行操作,您的Using
类就可能存在。唯一需要的是 - Task
类应该符合Disposable
。但这很容易:
extension WebSocketServiceInstance: Disposable {
func dispose() {
socket?.delegate = nil
socket?.close()
socket = nil
}
}