Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS Network Programming with Swift 2 Implementing a Forecast Client Concrete Types

Harish Yerra
Harish Yerra
10,031 Points

Not conforming to protocol 'APIClient'

I'm kind of struggling here and confused as to why I'm getting the error that I'm not conforming to the protocol when I clearly am.

I realize that the issue is in the init method. If I delete the APIKey parameter, remove the token property from the code below, and modify the convenience init to get rid of the APIKey everything works fine. But why can't I keep the token property? Clearly Pasan is able to do that.

Here's my code (exactly like Pasan's in the video):

import Foundation

final class ForecastAPIClient: APIClient {

    let configuration: NSURLSessionConfiguration
    lazy var session: NSURLSession = {
        return NSURLSession(configuration: self.configuration)
    }()

    private let token: String

    init(config: NSURLSessionConfiguration, APIKey: String) {
        self.configuration = config
        self.token = APIKey
    }

    convenience init(APIKey: String) {
        self.init(config: NSURLSessionConfiguration.defaultSessionConfiguration(), APIKey: APIKey)
    }
}

If I get rid of the token property and remove the APIKey like in the code below the errors vanish. Why? Am I doing something wrong?

import Foundation

final class ForecastAPIClient: APIClient {

    let configuration: NSURLSessionConfiguration
    lazy var session: NSURLSession = {
        return NSURLSession(configuration: self.configuration)
    }()


    init(config: NSURLSessionConfiguration) {
        self.configuration = config
    }

    convenience init() {
        self.init(config: NSURLSessionConfiguration.defaultSessionConfiguration())
    }
}

9 Answers

Aaron Bilenky
Aaron Bilenky
13,294 Points

I had the same problem. Remove

init(config: NSURLSessionConfiguration)

from the APIClient protocol definition in APIClient.swift. That should fix the error.

Harish Yerra
Harish Yerra
10,031 Points

Ya, actually what I did was to add APIKey to the init method in the protocol like this:

init(config: NSURLSessionConfiguration, APIKey: String)

It's easy to miss, but at 3:23 in the video Pasan says "We got rid of the init method in the protocol...", so although that particular step is missing, I believe that's what the lesson intends for us to do.

Additionally, in Swift 3, closure parameters need to be explicitly defined as '@escaping', which in turn means we need to update the protocol accordingly so the extension implementation matches the protocol, otherwise, we don't have a default implementation and the ForecastAPIClient class does not conform to the protocol.

protocol APIClient {
    var configuration: URLSessionConfiguration { get }
    var session: URLSession { get }

//    init(config: URLSessionConfiguration)

    func JSONTaskWithRequest(request: URLRequest, completion: @escaping JSONTaskCompletion) -> JSONTask
    func fetch<T>(request: URLRequest, parse: @escaping (JSON) -> T?, completion: @escaping (APIResult<T>) -> Void)
}
John Matthews
John Matthews
6,241 Points

Thanks Harish, that solved it for me. I'm still curious why Pasan didn't get the same error we did though.

Anthony Boutinov
Anthony Boutinov
13,844 Points

Harish, adding arbitrary additions like this on to the protocol breaks all the work we have done so far. What if in the future one wants to create a class that conforms to that protocol but does not require a key for its implementation.

The error that we get is probably due to the changes to Swift that were introduced with recent updates.

As for me, I have decided to remove the initializer from the protocol. I don't see any purpose in having it sit in there.

Bien Pham
PLUS
Bien Pham
Courses Plus Student 4,478 Points

It's because the implementation in the ForecastClient doesn't match the signature of the protocol for the init method in APIClient. So in order to correct that you either have to match the implementation to the protocol or match the protocol to the implementation. I've decided to add the parameter "APIKey: String" to the protocol since that seems like what Pasan intended but probably missed in a previous lesson.

protocol APIClient { var configuration: NSURLSessionConfiguration { get } var session: NSURLSession { get }

init(config: NSURLSessionConfiguration, APIKey: String)

func JSONTaskWithRequest(request: NSURLRequest, completion: JSONTaskCompletion) -> JSONTask
func fetch<T>(request: NSURLRequest, parse: JSON -> T?, completion: APIResult<T> -> Void)

}

Hello guys, I'm experiencing the same issue. I know that this has previously been brought up, but is there a correct way of doing this? Please bare in mind that I am now using Swift 3.0

         import Foundation

         final class ForecastAPIClient : APIClient {

         let configuration: URLSessionConfiguration
         lazy var session: URLSession = {
         return URLSession(configuration: self.configuration)
         }()

         private let token: String

        init(config: URLSessionConfiguration, APIKey: String) {
        self.configuration = config
        self.token = APIKey
        }

       convenience init(APIKey: String) {
       self.init(config: URLSessionConfiguration.default, APIKey: APIKey)
       }
       }
Bien Pham
Bien Pham
Courses Plus Student 4,478 Points

Check the protocol APIClient to see if you have each of the properties and functions compare that with the properties and functions that you've implemented in your ForecastAPIClient class if it doesn't match up that's the reason why your getting the error that it isn't conforming. Remember that the protocol is the "blueprint" to whatever class inherits it and so the inheriting class needs to conform and implement each of the properties and functions that are declared in the protocol.

Thanks Bien Pham, I am aware of this, however everything I try doesn't seem to work. What part of the APIClient Protocol should I conform to within the ForecastClient.Swift?

Here's some of my code within the APIClient:

     protocol APIClient {
     var configuration: URLSessionConfiguration { get }
     var session: URLSession { get }

     init(config: URLSessionConfiguration)

     func JSONTaskWithRequest(request: URLRequest, completion: JSONTaskCompletion) -> JSONTask
     func fetch<T>(request: URLRequest, parse: (JSON) -> T?, completion: (APIResult<T>) -> Void)
  }

   extension APIClient {
   func JSONTaskWithRequest(request: URLRequest, completion: @escaping JSONTaskCompletion) -> JSONTask {

(continued)

Bien Pham
Bien Pham
Courses Plus Student 4,478 Points

Looks like your signatures that don't match. Signature of your protocol init() has 1 parameter whereas your class init() has 2 parameters. And I can't tell if you actually created a "default implementation" via extensions for the fetch method or not. I assume you followed the tutorial so it's somewhere down below which should complete your implementation and conform to the requirements of the protocol.

Bien Pham, thank you for your help, but unfortunately I am still lost.

Dont do that guys!, just add the default init method also for the protocol so you will have:

    init(config: NSURLSessionConfiguration, APIKey: String) {
        self.configuration = config
        self.token = APIKey
    }
    init(config: NSURLSessionConfiguration) {
        self.configuration = config
        self.token = ""
    }
    convenience init(APIKey: String) {
        self.init(config: NSURLSessionConfiguration.defaultSessionConfiguration(), APIKey: APIKey)
    }

Remember that you can have the same method with different parameters. Also i thought about changing the APIClient protocol to this:

protocol APIClient {
    var session: NSURLSession { get }
    var configuration: NSURLSessionConfiguration { get }

    init(config: NSURLSessionConfiguration, APIKey: String)
    func JSONTaskWithRequest(request: NSURLRequest, completionHandler: JSONTaskCompletion) -> JSONTask
    func fetch<T>(request: NSURLRequest, parse: JSON -> T?, completion: APIResult<T> -> Void)
}

so the ForecastAPIClient would have only two initializers:

    init(config: NSURLSessionConfiguration, APIKey: String) {
        self.configuration = config
        self.token = APIKey
    }
    convenience init(APIKey: String) {
        self.init(config: NSURLSessionConfiguration.defaultSessionConfiguration(), APIKey: APIKey)
    }