【问题标题】:Extension of a protocol where the associatedType is class?扩展关联类型为类的协议?
【发布时间】:2018-01-11 13:09:46
【问题描述】:

我试过这样的:

protocol MyModelProtocol {
    var name: String { get set }
}

protocol MyProtocol {
    associatedtype Model: MyModelProtocol

    func changeModel(_ model: Model)
}

extension MyProtocol where Model: AnyObject {
}

编译器很高兴。但是,在此扩展中,编译器仍然不确定 Model 是类还是结构。示例:

extension MyProtocol where Model: AnyObject {
    func changeModel(_ model: Model) {
        model.name = "changed"
    }
}

因此,我收到错误消息:“无法分配给属性:'model' is a 'let' constant”

我如何告诉编译器在该协议扩展中关联的类型将始终是一个类?

顺便说一句,这只是一个简短的例子。我知道在这种情况下我可以使用 inout 参数,但它对我不起作用,因为我想像这样更改异步回调中的对象:

func changeModel(_ model: inout Model, completion: @escaping () -> Void) {
        Api.shared.doRandomAsyncStuff() { (_) in
            model.name = "changed"
            completion()
        }
    }

尝试这样做会导致错误:“转义闭包只能按值显式捕获 inout 参数”。

【问题讨论】:

  • 您是否也需要值类型(结构、枚举)采用的协议?否则你可以定义一个类协议:protocol MyModelProtocol: class { .. }
  • 是的,我愿意。我以前曾经有过,但由于我现在也想使用结构,所以我不得不删除该代码。

标签: ios swift generics protocols associated-types


【解决方案1】:

您可以只为 var 添加中间赋值。对于类/引用类型,这与在原始引用上设置属性具有相同的效果。对于结构类型,它会创建一个副本,这是行不通的,但应该通过对扩展的约束来避免。

func changeModel(_ model: Model, completion: @escaping () -> Void) {
    var modelRef = model
    Api.shared.doRandomAsyncStuff() { (_) in             
        modelRef.name = "changed"
        completion()
    }
}

【讨论】:

  • 太棒了!非常简单!我刚刚测试过,它成功了。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多