结合对服务器的访问在游乐场内而不是在函数内检索数据。为什么?
Combine access to server retrieves data within a playground but not within a function. Why?
以下代码产生了我期望的输出:
import UIKit
import Combine
let myURL = URL(string: "https://disease.sh/v3/covid-19/apple/countries/Canada")
// MARK: - Region
struct Region: Codable {
let country: String
let subregions: [String]
}
let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: myURL!)
.map { [=10=].data }
.print("Hello Data")
.decode(type: Region.self, decoder: JSONDecoder())
let cancellableSink = remoteDataPublisher
.sink(receiveCompletion: { completion in
print(".sink() received the completion", String(describing: completion))
switch completion {
case .finished:
break
case .failure(let anError):
print("received error: ", anError)
}
}, receiveValue: { someValue in
print(".sink() received \(someValue)")
})
// =====================================================================================================
print("The End.")
这是控制台中显示的输出。
可以看到,没有'cancel':
但是,当我将代码包装到函数 () 中时,'combine' 取消了输出。
getRegionList() 中的以下代码不会产生输出。
相反,它会收到 'cancel',如以下代码后的控制台所示:
import UIKit
import Combine
var regionList = [String]()
let simplePublisher = PassthroughSubject<String, Never>()
func getRegionList() {
let myURL = URL(string: "https://disease.sh/v3/covid-19/apple/countries/Canada")
// MARK: - Region
struct Region: Codable {
let country: String
let subregions: [String]
}
let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: myURL!)
.map { [=11=].data }
.print("Hello Data")
.decode(type: Region.self, decoder: JSONDecoder())
let cancellableSink = remoteDataPublisher
.sink(receiveCompletion: { completion in
print(".sink() received the completion", String(describing: completion))
switch completion {
case .finished:
break
case .failure(let anError):
print("received error: ", anError)
}
}, receiveValue: { someValue in
print(".sink() received \(someValue)")
})
}
getRegionList()
print("The End.")
函数取消,如控制台所示:
为什么?
唯一的代码差异是一个 被包装在一个简单的函数 中。
我怀疑某些 'lifespan' 一定已经过期了。
解决方案: 我应该使 concellableSink 全局化吗?
什么是正确的solution/syntax?
您需要保留对 AnyCancellable
的引用,否则当它被释放时,它会取消订阅,这就是您的函数 returns.
时发生的情况
通常,这是通过将引用存储在实例的 AnyCancellable
(或 Set<AnyCancellable>
)属性 中来处理的:
class Foo {
var cancellables: Set<AnyCancellable> = []
//...
func doSomething() {
somePublisher
.sink(...)
.store(in: &cancellables)
}
}
或者,sink
闭包可以保持对它自己的 AnyCancellable 的引用,并在收到值时释放它,但是如果发布者从不发布任何东西(尽管你可以使用 .timeout
运算符来缓解它):
func doSomething() {
let cancellable: AnyCancellable? = nil
cancellable = somePublisher
.sink(receiveCompletion: { completion in
// ...
cancellable = nil
}, receiveValue: { value in
//...
})
}
以下代码产生了我期望的输出:
import UIKit
import Combine
let myURL = URL(string: "https://disease.sh/v3/covid-19/apple/countries/Canada")
// MARK: - Region
struct Region: Codable {
let country: String
let subregions: [String]
}
let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: myURL!)
.map { [=10=].data }
.print("Hello Data")
.decode(type: Region.self, decoder: JSONDecoder())
let cancellableSink = remoteDataPublisher
.sink(receiveCompletion: { completion in
print(".sink() received the completion", String(describing: completion))
switch completion {
case .finished:
break
case .failure(let anError):
print("received error: ", anError)
}
}, receiveValue: { someValue in
print(".sink() received \(someValue)")
})
// =====================================================================================================
print("The End.")
这是控制台中显示的输出。
可以看到,没有'cancel':
但是,当我将代码包装到函数 () 中时,'combine' 取消了输出。
getRegionList() 中的以下代码不会产生输出。 相反,它会收到 'cancel',如以下代码后的控制台所示:
import UIKit
import Combine
var regionList = [String]()
let simplePublisher = PassthroughSubject<String, Never>()
func getRegionList() {
let myURL = URL(string: "https://disease.sh/v3/covid-19/apple/countries/Canada")
// MARK: - Region
struct Region: Codable {
let country: String
let subregions: [String]
}
let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: myURL!)
.map { [=11=].data }
.print("Hello Data")
.decode(type: Region.self, decoder: JSONDecoder())
let cancellableSink = remoteDataPublisher
.sink(receiveCompletion: { completion in
print(".sink() received the completion", String(describing: completion))
switch completion {
case .finished:
break
case .failure(let anError):
print("received error: ", anError)
}
}, receiveValue: { someValue in
print(".sink() received \(someValue)")
})
}
getRegionList()
print("The End.")
函数取消,如控制台所示:
为什么?
唯一的代码差异是一个 被包装在一个简单的函数 中。
我怀疑某些 'lifespan' 一定已经过期了。
解决方案: 我应该使 concellableSink 全局化吗?
什么是正确的solution/syntax?
您需要保留对 AnyCancellable
的引用,否则当它被释放时,它会取消订阅,这就是您的函数 returns.
通常,这是通过将引用存储在实例的 AnyCancellable
(或 Set<AnyCancellable>
)属性 中来处理的:
class Foo {
var cancellables: Set<AnyCancellable> = []
//...
func doSomething() {
somePublisher
.sink(...)
.store(in: &cancellables)
}
}
或者,sink
闭包可以保持对它自己的 AnyCancellable 的引用,并在收到值时释放它,但是如果发布者从不发布任何东西(尽管你可以使用 .timeout
运算符来缓解它):
func doSomething() {
let cancellable: AnyCancellable? = nil
cancellable = somePublisher
.sink(receiveCompletion: { completion in
// ...
cancellable = nil
}, receiveValue: { value in
//...
})
}