使用Xcode 11 beta 6,我试图为具有使用属性的类型声明一个协议@Published(但我猜这个问题可以推广到任何PropertyWrapper)。
final class DefaultWelcomeViewModel: WelcomeViewModel & ObservableObject {
@Published var hasAgreedToTermsAndConditions = false
}
Run Code Online (Sandbox Code Playgroud)
我试图声明:
protocol WelcomeViewModel {
@Published var hasAgreedToTermsAndConditions: Bool { get }
}
Run Code Online (Sandbox Code Playgroud)
这导致编译错误: Property 'hasAgreedToTermsAndConditions' declared inside a protocol cannot have a wrapper
所以我试着把它改成:
protocol WelcomeViewModel {
var hasAgreedToTermsAndConditions: Published<Bool> { get }
}
Run Code Online (Sandbox Code Playgroud)
并尝试
哪个不编译,DefaultWelcomeViewModel does not conform to protocol好吧,嗯,那我用不了,Published<Bool>试试吧!
struct WelcomeScreen<ViewModel> where ViewModel: WelcomeViewModel & ObservableObject {
@EnvironmentObject private var viewModel: …Run Code Online (Sandbox Code Playgroud) 有时我的视图模型使用@Published属性或 a PassthroughSubject,但我不希望它对外界可写。很简单,将其变成公共的AnyPublisher并将可写的保持为私有,如下所示:
class ViewModel {
@Published private var _models = ["hello", "world"]
var models: AnyPublisher<[String], Never> {
return $_models.eraseToAnyPublisher()
}
}
let viewModel = ViewModel()
viewModel.models.sink { print($0) }
Run Code Online (Sandbox Code Playgroud)
但是,如果您也希望能够“按需”读取该值怎么办?例如对于这种情况:
extension ViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(viewModel.models[indexPath.row])
}
}
Run Code Online (Sandbox Code Playgroud)
显然,上面的代码是行不通的。
我考虑过使用 a CurrentValueSubject,但它的值也是可写的,而且无论如何我都很难将 Publisher 变成 CurrentValueSubject 。
我当前的解决方案是在视图模型上添加类似的内容:
class ViewModel {
@Published private var _models = ["hello", "world"]
@Published var selectedIndex: Int?
var models: AnyPublisher<[String], Never> { …Run Code Online (Sandbox Code Playgroud)