简体   繁体   中英

Swift generic parameter cannot be bound to non-@objc protocol

The following code produces a compile error of "Generic parameter "T" cannot be bound to non-@objc protocol type 'AAA' on the fail line. When I use a class instead of a protocol, it works ok. Also, if I add an @objc to the protocol it also works, but only in 6.4 beta. Any suggestions would be helpful.

protocol AAA {
    var id: String { get set }
}

class BBB: AAA {
    var id: String = ""
}

class BBBService {
    func getAll<T:AAA>() -> [T] {
        var returnArray:[T] = [T]()

        return returnArray
    }
}

class TestIt
{
    func myTest() {
        var service = BBBService()
        var fail:[AAA] = service.getAll() // fails with Generic parameter "T" cannot be bound to non-@objc protocol type AAA
        var succeed:[BBB] = service.getAll()
    }
}

this also fails:

<T where T:AAA>

Update - from a practical perspective, adding the @objc causes other problems in my app. So, that is not an option at this point and time.

The trouble is with this line:

 getAll<T: AAA>() -> [T]

you are declaring that T must be a concrete type that implements the protocol AAA . It's important to distinguish between the protocol AAA , ie code like this:

func getAll() -> [AAA] {
    var returnArray: [AAA] = [BBB()]

    return returnArray
}

which works fine (returns an array of references to AAA -conforming objects, which could be of type BBB , or type CCC ), and this:

func getAll<T: AAA>() -> [T] {
    var returnArray: [T] = [] // what is T?  No idea.

    return returnArray
}

in which you are saying to the compiler “write me a version of getAll , in which T can be replaced by any specific type that implements AAA ”.

This is why your second version compiles - you're fixing T to be the actual type BBB .

Bear in mind, T might be a struct. In which case the array returned must be sized specifically for whatever struct is being held, right there as a value within the array. As opposed to if the protocol was @objc in which case it would at least be known to only be a class reference of a fixed size.

If what you actually want is an array of protocols, you should remove the generic placeholder and just return an array of protocols:

func getAll() -> [AAA] {
    var returnArray: [AAA] = []

    return returnArray
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM