2

Background

Let's consider the following working code

protocol CanFly { }

protocol Container {
    associatedtype ContentType
    var value: ContentType? { get }
}

class Box<V>: Container {
    var value: V?
}

let box = Box<CanFly>()
box.value // <- has type `CanFly?`

Here Box accepts a protocol as generic type, beautiful isn't it?

Things get harder

Now I want to do a "small" change, I make the value property in Box weak

class Box<V>: Container {
    weak var value: V?
}

And of course I get this error

class Box<V>: Container {
    weak var value: V? // 'weak' must not be applied to non-class-bound 'V'; consider adding a protocol conformance that has a class bound
}

I try to fix it constraining V to be an AnyObject

class Box<V:AnyObject>: Container {
    weak var value: V?
}

And I get this error

let box = Box<CanFly>() // 'Box' requires that 'CanFly' be a class type

The problem

The problem here is that since I defined V:AnyObject I can no longer use the protocol CanFly as generic type of Box.

The question

I want

  1. to be able to use a protocol as generic type of Box
  2. AND the Box#value property to be weak

How can I do that?

Final considerations

I am looking for something like this

class Box<V:ProtocolForClassOnly>: Container {
    weak var value: V?
}

P.S. The closest question on StackOverflow I could find is this one but unfortunately hasn't helped me.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • I'm confused about your P.S. That question seems identical to your question, and the answer appears correct. Do you believe that answer is not correct? Or are you just hoping that answer isn't correct? (It is correct; you can't do what you're trying to do exactly the way you're trying to do it.) – Rob Napier Jul 16 '19 at 17:22
  • If you're looking for more solutions than the ones there, then I would look hard at using closures (that may have a `weak` capture) rather than trying to create multiple levels of protocols like this. If you can discuss your underlying problem that this solves, I suspect we can build a closure-based solution and avoid delegate-style patterns. – Rob Napier Jul 16 '19 at 17:25

1 Answers1

-1

So constrain your CanFly protocol to type AnyObject:

protocol CanFly: AnyObject { }

protocol Container {
    associatedtype ContentType
    var value: ContentType? { get }
}

class Box<V>: Container {
    var value: V?
}

Then your code works:

func foo() {
    let box = Box<CanFly>()
    print(type(of:box.value))
}
Duncan C
  • 128,072
  • 22
  • 173
  • 272