当前位置: 首页 > 面试题库 >

Swift:无法将值分配给协议的属性?

黄修永
2023-03-14
问题内容

A类提供一个字符串值。类B在其内部具有两个A类型的成员,并提供一个计算属性“ v”来选择其中之一。

class A {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B {
    var v1: A?
    var v2: A = A(value: "2")

    private var v: A {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue
        }
    }
}

这段代码很简单,可以正常工作。由于A和B都具有成员“值”,因此我将其设为这样的协议:

protocol ValueProvider {
    var value: String {get set}
}

class A: ValueProvider {
    var value: String

    init(value: String) {
        self.value = value
    }
}

class B: ValueProvider {
    var v1: ValueProvider?
    var v2: ValueProvider = A(value: "2")

    private var v: ValueProvider {
        return v1 ?? v2
    }

    var value: String {
        get {
            return v.value
        }
        set {
            v.value = newValue // Error: Cannot assign to the result of the expression
        }
    }
}

如果我更改以下代码

v.value = newValue

var v = self.v
v.value = newValue

它再次起作用!

这是Swift的错误,还是协议属性的特殊之处?


问题答案:

您必须将协议定义为class协议:

protocol ValueProvider : class {
    var value: String {get set}
}

然后

var value: String {
    get { return v.value }
    set { v.value = newValue }
}

编译并按预期方式工作(即,将新值分配给v1if v1 != nil所引用的对象,v2否则分配给否则所引用的对象)。

v是类型的只读计算属性ValueProvider。通过将协议定义为类协议,编译器知道这v引用类型 ,因此v.value
即使引用本身是常量,也可以修改其属性。

您的初始代码示例有效,因为该 v属性具有A引用类型的类型。

和您的解决方法

set {
    var tmp = v1 ?? v2
    tmp.value = newValue
}

之所以起作用,是因为可以在任何情况下(值类型或引用类型)设置 变量的 (读写)属性。



 类似资料:
  • 问题内容: 请参见下面的自包含示例。编译器在最后一行(由标记为)报告错误,在该行中,我将实例分配给它(根据我的最佳判断)符合的协议类型。如何编译?我究竟做错了什么?还是这个编译器问题? 编辑: 即使我明确地向下转换了上面的返回类型(以便上面的代码片段的最后一行读取),如安东尼奥在调用函数时仍然存在编译错误: 问题答案: 首先,您想从devforums上读到规范的线程。您特别想跳过阅读jckarte

  • 问题内容: 假设我有以下协议: 而且我有以下结构: 如您所见,我必须“遵循”结构A和结构B中的Identifiable协议。但是想象一下,如果我还有N个需要符合该协议的结构……我不想“复制/粘贴” ‘一致性(变量ID:整数,变量名称:字符串) 所以我创建了一个 协议扩展 : 现在,通过此扩展,我可以创建符合Identifiable协议的结构,而不必同时实现这两个属性: 现在的问题是我不能为id属性

  • 问题内容: 更新到xcode 8 beta 6后,出现错误 无法将’()-> Void’类型的值分配给’(()-> Void)!’ 在以下func块的第三行: 关于修复的任何建议? 问题答案: 看来您的问题与此有关: SE-0103 尝试将您的方法标头追踪到: 与往常一样,来自新Beta的诊断消息是如此混乱和不足,但是将您的媒体资源设置为非可选将为您提供更多有用的信息。

  • 问题内容: 我有一个协议,该协议继承自另一个协议,并且满足扩展要求。 还有另一种协议,其要求()应该为。 现在,如果我尝试使用as ,那么它将无法编译。它说, 推断的类型“地址”(通过匹配要求“ valueForDetail”)无效:不符合“ Validator”。 这种用法非法吗?我们不能像所有的那样用它代替。 下面是我正在尝试的代码。 更新: 提交了一个错误。 问题答案: David已经提到的

  • 协议(Protocols)为方法,属性和其他需求功能提供了蓝图。 它为方法或属性骨架而不是实现。 通过定义类,函数和枚举,可以进一步完成方法和属性的实现。 协议的一致性满足了协议要求的方法或属性。 语法 协议也遵循与类,结构和枚举类似的语法 - 协议在类,结构或枚举类型名称之后声明。 单个和多个协议声明也是可以的。 如果定义了多个协议,则必须用逗号分隔。 当要为超类定义协议时,协议名称应使用逗号跟

  • 协议规定了用来实现某一特定功能所必需的方法和属性。 任意能够满足协议要求的类型被称为遵循(conform)这个协议。 类,结构体或枚举类型都可以遵循协议,并提供具体实现来完成协议定义的方法和功能。 语法 协议的语法格式如下: protocol SomeProtocol { // 协议内容 } 要使类遵循某个协议,需要在类型名称后加上协议名称,中间以冒号:分隔,作为类型定义的一部分。遵循