为什么在写入可选 属性 时 Combine 分配会崩溃?
Why does Combine assign crash when writing to an optional property?
此代码崩溃(“在展开可选值时意外发现 nil”)
import Combine
class Receiver {
var value: Int!
var cancellables = Set<AnyCancellable>([])
init(_ p: AnyPublisher<Int,Never>) {
p.assign(to: \.value, on: self).store(in: &cancellables)
}
}
let receiver = Receiver(Just(5).eraseToAnyPublisher())
如果我使用 p.sink { self.value = [=12=] }.store(in: &cancellables)
而不是分配,它不会崩溃,如果我不为 value
-属性 使用可选,它也不会崩溃。
对我来说,这看起来像是 Swift 的构造函数代码中的错误,但也许我忽略了什么?
肯定是Combine的一个bug,它在赋值的时候访问了值。如果您将其更改为常规可选而不是隐式解包(将 !
更改为 ?
),它将正常工作。在大多数情况下,您应该避免隐式解包 Optional,除非它们对于设计约束是绝对必要的。
问题
value
是一个“隐式展开的可选”(因此是一个 Optional
),但是你的 AnyPublisher
的 Output
是 Int
-这是 不是 而是 Optional
.
解决方案
将 AnyPublisher
的 Output
从 Int
更改为 Int?
,这样它也将是 Optional
。这是应用此修复程序的代码示例:
import Combine
class Receiver {
var value: Int!
var cancellables = Set<AnyCancellable>([])
init(_ p: AnyPublisher<Int?, Never>) { // `Output` was changed from `Int` to `Int?` here.
p.assign(to: \.value, on: self).store(in: &cancellables)
}
}
let receiver = Receiver(Just(5).eraseToAnyPublisher())
此代码崩溃(“在展开可选值时意外发现 nil”)
import Combine
class Receiver {
var value: Int!
var cancellables = Set<AnyCancellable>([])
init(_ p: AnyPublisher<Int,Never>) {
p.assign(to: \.value, on: self).store(in: &cancellables)
}
}
let receiver = Receiver(Just(5).eraseToAnyPublisher())
如果我使用 p.sink { self.value = [=12=] }.store(in: &cancellables)
而不是分配,它不会崩溃,如果我不为 value
-属性 使用可选,它也不会崩溃。
对我来说,这看起来像是 Swift 的构造函数代码中的错误,但也许我忽略了什么?
肯定是Combine的一个bug,它在赋值的时候访问了值。如果您将其更改为常规可选而不是隐式解包(将 !
更改为 ?
),它将正常工作。在大多数情况下,您应该避免隐式解包 Optional,除非它们对于设计约束是绝对必要的。
问题
value
是一个“隐式展开的可选”(因此是一个 Optional
),但是你的 AnyPublisher
的 Output
是 Int
-这是 不是 而是 Optional
.
解决方案
将 AnyPublisher
的 Output
从 Int
更改为 Int?
,这样它也将是 Optional
。这是应用此修复程序的代码示例:
import Combine
class Receiver {
var value: Int!
var cancellables = Set<AnyCancellable>([])
init(_ p: AnyPublisher<Int?, Never>) { // `Output` was changed from `Int` to `Int?` here.
p.assign(to: \.value, on: self).store(in: &cancellables)
}
}
let receiver = Receiver(Just(5).eraseToAnyPublisher())