类型“任何 ProtocolName”不能符合“(ProtocolName 的继承协议)”

ste*_*ser 9 swift swiftui combine

我有一个符合 ObservableObject 的 ProtocolName。然后我就有了符合 ProtocolName 的 ClassName。

但是,当我尝试使用 @ObservedObject serviceName: ProtocolName = ClassName 时,它​​无法构建并显示以下消息:“Type 'any ProtocolName' 无法符合 'ObservableObject'”

我做错了什么以及如何解决这个问题?

例子:

protocol ProtocolName: ObservableObject {
    let random: String
}

class ClassName: ProtocolName {
    let random: String
}

@ObservedObject serviceName: ProtocolName = ClassName()
Run Code Online (Sandbox Code Playgroud)

Sco*_*son 18

当你写这样一行时:

@ObservedObject var observeMe: ProtocolName
Run Code Online (Sandbox Code Playgroud)

你是说这observeMe是一个盒子,可以容纳任何符合ProtocolName协议的东西”

该盒子的类型any ProtocolName称为existential

但盒子本身不符合ProtocolName(并且通过扩展也不符合ObservableObject)。盒子里面的东西可以,但盒子本身却不能。

所以编译器抱怨说,类型为的存在any ProtocolName不是一个ObservableObject

您可以使用以下语法使该框更加明显和明确any ProtocolName

import SwiftUI
import Combine

protocol ProtocolName: ObservableObject {
    var someValue: Int { get }
}

class MyClass: ProtocolName {
    @Published var someValue: Int = 42
}

struct SomeStruct : View {
    @ObservedObject var observeMe: any ProtocolName = MyClass()
    
    var body: some View {
        Text("Hello.")
    }
}
Run Code Online (Sandbox Code Playgroud)

您仍然会看到该错误。

要解决这个问题,您@ObservedObject必须是符合以下条件的具体类型ProtocolName

import SwiftUI
import Combine

protocol ProtocolName: ObservableObject {
    var someValue: Int { get }
}

class MyClass: ProtocolName {
    @Published var someValue: Int = 42
}

struct SomeStruct : View {
    @ObservedObject var observeMe: MyClass = MyClass()
    
    var body: some View {
        Text("Hello.")
    }
}

let myView = SomeStruct()
Run Code Online (Sandbox Code Playgroud)

或者,您可以向视图添加类型参数,以便在创建视图时有一个符合该视图所用协议的特定类型:

import SwiftUI
import Combine

protocol ProtocolName: ObservableObject {
    var someValue: Int { get set }
}

class MyClass: ProtocolName {
    @Published var someValue: Int = 42
}

struct SomeStruct<T : ProtocolName> : View {
    @ObservedObject var observeMe:T
    
    var body: some View {
        Text("Hello.")
        Button(action: {observeMe.someValue = 3}) {
            Text("Button")
        }
    }
}

let myView = SomeStruct(observeMe: MyClass())
Run Code Online (Sandbox Code Playgroud)

  • 我的意思是,如果没有 SwiftUI 的限制,您可以“编程接口”,这意味着 View 只会知道 viewModel 接口,并且您可以决定在应用程序的根目录中仅使用一次的具体类。这允许轻松地为单元测试/演示应用程序创建“真实”依赖项或模拟依赖项,而无需触及代码的其余部分。现在从我所看到的 swift UI 强制程序员在使用它的任何地方声明依赖项的具体实例。这不是一个大问题吗,因为它使得模拟表示层逻辑(视图模型)不再可能了? (2认同)