2

I've tried to use generic type with protocol:

class Weak<T: AnyObject> {
    weak var value: AnyObject?
    init (value: AnyObject) {
        self.value = value
    }
}

protocol SomeProtocol: AnyObject {
    func doSomething()
}

func createWeak(object: SomeProtocol) -> Weak<SomeProtocol> {
    return Weak<SomeProtocol>(value: object)
}

class SomeClass: SomeProtocol {
    func doSomething() {
        print("Some 2")
    }
}

let temp =  SomeClass()
let weakObject = createWeak(object: temp)
weakObject.value?.doSomething()

And got the compiler error: error: 'SomeProtocol' is not convertible to 'AnyObject' return Weak(value: object)

But without AnyObject constraint it works fine

class Weak<T> {
var value: T?
    init (value: T) {
        self.value = value
    }
}

protocol Protocol {
    func doSomething()
}

class Class: Protocol {
    func doSomething() {
        print("This is class")
    }
}

func createWeak(object: Protocol) -> Weak<Protocol> {
    return Weak(value: object)
}

let temp =  Class()
let weakObject = createWeak(object: temp)
weakObject.value?.doSomething()

Why I can't use protocols inherited form AnyObject in generic classes?

  • This great answer might help you: https://stackoverflow.com/a/43408193/1974224 – Cristik Feb 27 '18 at 18:14
  • "I've tried to use generic type with protocol." And that was your first mistake. :D But quite seriously, it is very tricky to mix generics and protocols, and it is rarely worth the complexity. As @Cristik notes, your approach will not work in Swift. – Rob Napier Feb 27 '18 at 18:20
  • It's worth noting that your `Weak` doesn't make sense as written. You're not using `T`. What I think you meant was `weak var value: T?` and `init(value: T)`. This won't help your underlying problem. As Cristik notes, this entire approach is not possible. You cannot create `Weak`. The type must be concrete, not a protocol. – Rob Napier Feb 27 '18 at 18:28

1 Answers1

3

Swift protocols are incomplete types, which means that you can't use them in places like generic arguments, as the compiler needs to know the whole type details so it can allocate the proper memory layout.

Your createWeak function can still be used if you make it generic:

func createWeak<T: SomeProtocol>(object: T) -> Weak<T> {
    return Weak<T>(value: object)
}

The above code works because the compiler will generate at compile time a function mapped to the concrete type you pass.

Even better, you can make the initializer generic, and convert Weak to a struct (value types are preferred Swift over reference ones):

struct Weak<T: AnyObject> {
    weak var value: T?

    init(_ value: T) {
        self.value = value
    }
}

which you can use it instead of the free function:

let weakRef = Weak(temp)
Cristik
  • 30,989
  • 25
  • 91
  • 127