Protocol of reference type to generic constraint of type AnyObject
Asked Answered
C

3

6

I have a generic struct declared as follows:

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

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

And a protocol:

protocol SomeProtocol: class {

}

But I'm not able to declare a variable of type of WeakReference<SomeProtocol>, the compiler complains that

'WeakReference' requires that SomeProtocol be a class type

Interestingly, in Swift, the class is a typealias of AnyObject.

I actually want to hold an array of WeakReference<SomeProtocol> because the array holds strong references.

Class-only generic constraints in Swift is a similar question but doesn't really solve this problem.

How can we pass the SomeProtocol to WeakReference?

EDIT: The following scenario compiles fine, but we lose the ability to hold weak reference:

struct Reference<T> {
    var value: T?

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

var array: [Reference<SomeProtocol>] = []
Cult answered 6/8, 2018 at 11:38 Comment(0)
B
1

Thats simple. You are passing SomeProtocol which is a protocol. You need to pass there specific class type.

Eample:

class SomeImplementation: SomeProtocol {
}

var weakSome: WeakReference<SomeImplementation> = ...

Or you can bypass it by marking the protocol with @objc annotation, but I am not a fan of this approach.

@objc protocol SomeProtocol: class {

}

var weakSome: WeakReference<SomeProtocol> = ...

Try checking this answer, it might provide you more context on the issue.

Bearish answered 6/8, 2018 at 12:33 Comment(3)
The problem is I want to hold an array of weak references of the classes that conform to protocol SomeProtocol. It works if we don't have the constraint <T: AnyObject>. But then we can't have weak references.Cult
I have edited the the question to show this same case.Cult
I would suggest creating a specific SomeWeakBox where the value property will be SomeProtocol and definition of some protocol will be constrained to class types protocol SomeProtocol: class. Then you can simply have array let array: [SomeWeakBox] = []Circumspection
C
1

What do you think about this approach?

class WeakReference<T> {
    weak var value: AnyObject?

    init(value: T?) {
        self.value = value as? AnyObject
    }
}

protocol SomeProtocol: class {

}

class A: SomeProtocol { }

let araayOfSomeProtocolObjects: [SomeProtocol] = (0...5).map {_ in A() }
let arrayOfWeakReferences: [WeakReference<SomeProtocol>] = araayOfSomeProtocolObjects.map { WeakReference(value: $0) }

for item in arrayOfWeakReferences {
    print(item.value is A) // true
}

enter image description here

Coop answered 6/8, 2018 at 13:2 Comment(5)
How do I hold an array of weak references of objects which conform to SomeProtocol with this approach?Cult
This doesn't compile. Can't use WeakReference<SomeProtocol>. That's the whole problem.Cult
@Cult strange, i have compiled without problem on latest Xcode. Can you provide error image or something?Coop
@Cult I also attached playground screenshotCoop
I'm sorry I overlooked that you removed the generic constraint in WeakReference. This compiles and works fine. The only downside is that we have to typecast the value to SomeProtocol every time we use it.Cult
P
1

I think this should solve your problem.

struct WeakReference<T> {
    private weak var privateRef: AnyObject?
    var ref: T? {
        get { return privateRef as? T }
        set { privateRef = newValue as AnyObject }
    }

    init(_ ref: T? = nil) {
        self.ref = ref
    }
}

// usage
protocol MyProto: class { }
extension UIViewController: MyProto { }

let vc = UIViewController()
var weakRef = WeakReference<MyProto>(vc)
print(weakRef.ref)

You obviously can use WeakReference with non class protocol or non bridged value types. If you try that, you'll get always nil.

P.S. : Try this code on a real Xcode project because in the Playground doesn't work as expected.

Potency answered 8/12, 2018 at 16:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.