Alex
Alex

Reputation: 8991

Generic protocol extension and `Self`

I have a protocol that defines the ability to fetch an array of objects from a server. Result is defined in Alamofire:

protocol BulkFetchable {

    static func fetch(limit : Int, skip : Int, completionHandler : ((request : NSURLRequest?, response : NSHTTPURLResponse?, result : Result<[Self]?>) -> Void)) -> Request

}

I extend this protocol with a generic implementation (ignore the fact that that the endpoint is fixed for the purposes of this question):

extension BulkFetchable where Self : Mappable {

    static func fetch(limit: Int, skip: Int, completionHandler: ((request: NSURLRequest?, response: NSHTTPURLResponse?, result: Result<[Self]?>) -> Void)) -> Request {
        return Alamofire.request(.GET, "http://localhost:4567/users.json", parameters: ["limit" : limit, "skip" : skip], encoding: .URL, headers: nil).responseArray(completionHandler)
    }

}

I'm using an extension to Alamofire Request that converts a JSON response to an optional array of type T, where T adopts Mappable:

extension Request {

func responseArray <T : Mappable> (completionHandler: (NSURLRequest?, NSHTTPURLResponse?, Result<[T]?>) -> Void) -> Self {
    return responseJSON(completionHandler: { (req, res, result) -> Void in
        switch result {
        case .Success(let json):
            completionHandler(req, res, .Success(Mapper<T>().mapArray(json)))
            break
        case .Failure(let data, let error):
            completionHandler(req, res, .Failure(data,error))
            break
        }
    })
}

}

Then, I give my User model this ability:

extension User : BulkFetchable {}

Alas, I receive the error:

Protocol 'BulkFetchable' requirement 'fetch(_:skip:completionHandler:)' cannot be satisfied by a non-final class ('User') because it uses 'Self' in a non-parameter, non-result type position

What can I do to get around this? I would expect that Self automatically becomes User in the context of the extension to User, but that's probably due to my lack of understanding.

Upvotes: 1

Views: 1210

Answers (1)

ByteWrencher
ByteWrencher

Reputation: 61

I was doing something similar and stumbled on the same error.

My limited understanding of this (which comes mostly from two videos recorded at WWDC 2015 here and here) suggests that your class User needs to be declared as:

final class User {...}

This would be because the fetch() call doesn't have to be overridden by a subclass.

fetch() is supposed to return a homogenous array of Self (in this case User) and if User was subclassed (and fetch() overriden) it would return an array of the subclass. Or in an easily imagined world an array of User and its subclasses. Not what the super class BulkFetchable was expecting!

Upvotes: 6

Related Questions