具有关联类型的Swift协议中的弱属性要求

Vla*_*lad 8 ios swift

我想写一个弱属性要求的协议.符合它的类必须能够为此属性指定任何类型.此外,我不想指定实际类型,因此它应该是使用某些协议指定的类型.此代码显示了我对非弱属性的想法:

protocol ObjectProtocol: class {
  typealias PropertyType
  var property: PropertyType {get set}
}

protocol FirstPropertyProtocol: class {}
protocol SecondPropertyProtocol: class {}

class FirstObjectImpl: ObjectProtocol {
  var property: FirstPropertyProtocol?
}

class SecondObjectImpl: ObjectProtocol {
  var property: SecondPropertyProtocol?
}
Run Code Online (Sandbox Code Playgroud)

它按预期工作.

我试图为弱属性做同样的事情:

protocol ObjectProtocol: class {
  typealias WeakPropertyType: AnyObject //must be a class type
  weak var weakProperty: WeakPropertyType? {get set}
}

protocol WeakPropertyProtocol: class {}

class ObjectImpl: ObjectProtocol {
  weak var weakProperty: WeakPropertyProtocol?
}
Run Code Online (Sandbox Code Playgroud)

我收到了编译错误:

类型'ObjectImpl'不符合协议'ObjectProtocol'

有什么方法可以让我的工作吗?

Vla*_*lad 5

我让它与 WeakPropertyProtocol 的 @objc 属性一起使用:

protocol ObjectProtocol: class {
  typealias WeakPropertyType: AnyObject //must be a class type
  weak var weakProperty: WeakPropertyType? {get set}
}

@objc protocol WeakPropertyProtocol {}

class SomeObjectImpl: ObjectProtocol {
  weak var weakProperty: WeakPropertyProtocol?
}
Run Code Online (Sandbox Code Playgroud)

这不是最好的解决方案,因为我担心苹果文档的这条说明

另请注意,@objc 协议只能由继承自 Objective-C 类或其他 @objc 类的类采用。

我可以忍受这个限制,但如果有更好的解决方案,我将不胜感激。


Ado*_*els 2

作为与 Xcode 14.0 捆绑在一起的 Swift 5.7,编译器会发出错误:“'weak' 无法应用于协议中的属性声明”

可能的协议限制解决方法使用计算变量和由计算变量包装的补充“弱”变量。

解决方法 1:此解决方法不会强制应用协议的类型将属性设置为弱

protocol SharedInformation {
  var name: UIViewController? { get set }
}

class Country: SharedInformation {

  private weak var _name: UIViewController?

  var name: UIViewController? {
    get {
      _name
    }
    set {
      _name = newValue
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

解决方法 2:此方法强制应用协议的类型使用弱存储包装属性。

protocol SharedInformation {
  var name: Weak<UIViewController> { get set }
}

class Country: SharedInformation {
  
  var name: Weak<UIViewController> = .init()
  
  func usage() {
    // set
    name.wrappedValue = UIViewController()
    // get
    let value = name.wrappedValue
  }
}

public struct Weak<Wrapped: AnyObject> {
  
  public weak var wrappedValue: Wrapped?
  
  public init(_ value: Wrapped? = nil) {
    self.wrappedValue = value
  }
}
Run Code Online (Sandbox Code Playgroud)