Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weak property requirement in Swift protocol with associated type

Tags:

ios

swift

I want to write a protocol with weak property requirement. Class that conforms it must be able to specify any type for this property. Also I don't want to specify an actual type, so it should be a type specified with some protocol. This code shows my idea for non-weak property:

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?
}

It works as expected.

I tried to do the same for weak property:

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?
}

And I got a compiler error:

Type 'ObjectImpl' does not conform to protocol 'ObjectProtocol'

Is there any way I can make this work?

like image 981
Vlad Avatar asked Mar 02 '16 18:03

Vlad


People also ask

What are associated types in Swift?

An associated type gives a placeholder name to a type that's used as part of the protocol. The actual type to use for that associated type isn't specified until the protocol is adopted. Associated types are specified with the associatedtype keyword.

Can only be used as a generic constraint because it has self or associated type requirements?

Protocol 'SomeProtocol' can only be used as a generic constraint because it has Self or associated type requirements. Code that uses a protocol that relies on associated types pays the price. Such code must be written using generic types. Generic types are also placeholders.

CAN protocols have properties in Swift?

A protocol can have properties as well as methods that a class, enum or struct conforming to this protocol can implement. A protocol declaration only specifies the required property name and type.

Is it possible to prevent the adoption of a protocol by a struct?

A protocol defines a blueprint of methods, properties, and other requirements. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. But there would be a time when you want to restrict protocols to be adopted by a specific class.


2 Answers

I made it work with @objc attribute for WeakPropertyProtocol:

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?
}

It's not a best solution because I concern about this note from apple doc

Note also that @objc protocols can be adopted only by classes that inherit from Objective-C classes or other @objc classes.

I can live with this restriction but I will appreciate any better solution.

like image 140
Vlad Avatar answered Sep 20 '22 13:09

Vlad


I don't believe a protocol can enforce weak-ness. For example:

protocol ObjectProtocol: class {
  weak var weakProperty: AnyObject? {get set}
}

class ObjectImpl1: ObjectProtocol {
  weak var weakProperty: AnyObject?
}

class ObjectImpl2: ObjectProtocol {
  var weakProperty: AnyObject?
}

These both compile ok, even though the protocol has weak but ObjectImpl2 does not implement it.

EDIT: Is this what you're after?...

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

protocol WeakPropertyProtocol: class {}

class ObjectImpl: ObjectProtocol {
  typealias WeakPropertyType = WeakPropertyProtocol
  weak var weakProperty: WeakPropertyProtocol?
}

This implementation requires use of Any rather than AnyObject, since WeakPropertyProtocol is a protocol rather than a class.

Or this?...

protocol WeakPropertyProtocol: class {}

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

class MyWeakClass: WeakPropertyProtocol {

}

class ObjectImpl: ObjectProtocol {
  typealias WeakPropertyType = MyWeakClass
  weak var weakProperty: MyWeakClass?
}

Either way, I think the key is in defining which class/protocol to use for WeakPropertyType.

like image 36
Michael Avatar answered Sep 20 '22 13:09

Michael