Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

type A requires that type B be a class type swift 4

Tags:

swift

swift4

the following code gives me a compile error

'WeakReference' requires that 'ServiceDelegate' be a class type

protocol ServiceDelegate: AnyObject {     func doIt() }  class SomeClass() {     // compile error occurs in this line     private var observers = [WeakReference<ServiceDelegate>]() } 

WeakReference code:

final class WeakReference<T: AnyObject> {      private(set) weak var value: T?      init(value: T?) {         self.value = value     } } 

How can I fix this error? Delegate should be declared correctly as per this site.

What I have tried so far:

  • Changing the delegate protocol conformance from AnyObject to class does not solve the problem.
  • Try the above code in a clean playground.
like image 294
christopher.online Avatar asked Jul 23 '18 20:07

christopher.online


2 Answers

You can't have a WeakReference<ServiceDelegate>. ServiceDelegate itself is not an AnyObject, it just requires that anything that conforms to it be an AnyObject.

You would need to make SomeClass generic and use the generic type as the type for the WeakReference:

class SomeClass<T: ServiceDelegate> {     private var observers = [WeakReference<T>]() } 

If the generic on SomeClass is too constricting and you want to be able to have instances of multiple unrelated classes as observers then I would do it by abandoning the generic parameter on WeakReference:

final class WeakServiceDelegate {     private(set) weak var value: ServiceDelegate?      init(value: ServiceDelegate?) {         self.value = value     } }  class SomeClass {     private var observers = [WeakServiceDelegate]() } 

Alternatively you could make WeakReference conditionally conform to ServiceDelegate:

extension WeakReference: ServiceDelegate where T: ServiceDelegate {     func doIt() {         value?.doIt()     } } 

And then use an array of ServiceDelegate in SomeClass:

class SomeClass {     private var observers = [ServiceDelegate]()      func addObserver<T: ServiceDelegate>(_ observer: T) {         observers.append(WeakReference(value: observer))     } } 
like image 59
dan Avatar answered Sep 20 '22 19:09

dan


As you see, ServiceDelegate is a protocol, not a class type. Even if all types which can conform to ServiceDelegate are class types, ServiceDelegate itself is not a class type. It is the fact of the pure Swift protocols currently.

Try @obc, Objective-C protocols are a bit different:

@objc protocol ServiceDelegate {     func doIt() } 

You may want to exclude Objective-C something and to make some pure Swift classes conform to ServiceDelegate, but I cannot find other ways around.

like image 36
OOPer Avatar answered Sep 23 '22 19:09

OOPer