I am currently working my way through he Treehouse IOS Swift course, and we are building a weather app. I've gotten to a point where I keep getting an error that my class isn't conforming to my protocol, but I can't figure out why.
Here is my protocol declaration:
public protocol APIClient {
var configuration: URLSessionConfiguration { get }
var session: URLSession { get }
func JSONTaskWithRequest(request: URLRequest, completion: JSONTaskCompletion) -> JSONTask
func fetch<T: JSONDecodable>(request: URLRequest, parse: (JSON) -> T?, completion: (APIResult<T>) -> Void)
}
And then I have a protocol extension where I have default implementations of my two methods declared in the protocol, and one of the methods is calling the other method, as you can see below.
public extension APIClient {
func JSONTaskWithRequest(request: URLRequest, completion: @escaping JSONTaskCompletion) -> JSONTask {
let task = session.dataTask(with: request) { data, response, error in
guard let HTTPResponse = response as? HTTPURLResponse else {
let userInfo = [
NSLocalizedDescriptionKey: NSLocalizedString("Missing HTTP Response", comment: "")
]
let error = NSError(domain: BPSnetworkingErrorDomain, code: MissingHTTPReponseError, userInfo: userInfo)
completion(nil, response as! HTTPURLResponse, error)
return
}
if data == nil {
if let error = error {
completion(nil, response as! HTTPURLResponse, error as NSError?)
}
} else {
switch HTTPResponse.statusCode {
case 200:
do {
let JSON = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: AnyObject]
completion(JSON, HTTPResponse, nil)
} catch let error as NSError {
completion(nil, HTTPResponse, error)
}
default: print("Received HTTP Response \(HTTPResponse.statusCode) - not handled")
}
}
}
return task
}
public func fetch<T>(request: URLRequest, parse: @escaping (JSON) -> T?, completion: @escaping (APIResult<T>) -> Void) {
let task = JSONTaskWithRequest(request: request) { json, response, error in
DispatchQueue.main.async {
guard let json = json else {
if let error = error {
completion(.Failure(error))
} else {
let error = "Something is really wrong. There was no JSON object created, but there was no error either."
completion(.Failure(error as! Error))
}
return
}
if let value = parse(json) {
completion(.Success(value))
} else {
let error = NSError(domain: BPSnetworkingErrorDomain, code: unexpectedResponseError, userInfo: nil)
completion(.Failure(error))
}
}
}
task.resume()
}
}
Then I have my class declaration where I am getting my non conformity error.
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)
}
func fetchCurrentWeather(coordinate: Coordinate, completion: @escaping (APIResult<CurrentWeather>) -> Void) {
let request = Forecast.Current(token: self.token, coordinate: coordinate).request
fetch(request: request, parse: { (JSON) -> CurrentWeather? in
if let currentWeatherDictionary = JSON["currently"] as? [String: AnyObject] {
return CurrentWeather(JSON: currentWeatherDictionary)
} else {
return nil
}
}, completion: completion)
}
}
I've done a lot of reading around for several hours trying to figure out what is going on here. From what I understand, I shouldn't need to define those two methods in my class since they have default implementations in the protocol extension. I came across the issue of public/internal types and things like that, that someone else was having here on StackExchange with their extensions, (as you an see by my labeling things public and what not), but that didn't seem to help in my case. The only way I've been able to get the error to go away, is by commenting out those method declarations in the original protocol declaration. Which seems to indicate to me that either the class, or the protocol, or something isn't seeing the extension for some reason, however, if I command click on the fetch
method call in the class declaration, it takes me to the definition of it in the extension. I haven't been able to find a solution, or even someone who is doing this similar thing, there are several people on Treehouse that seem to be having this same issue as well.
Also, I download the teachers code, and converted it to Swift 3, and it was getting the same error as well, so maybe it's an issues with having a different version of Xcode the what he used when he made the video?
I feel like I'm kind of grasping at straws a little bit, but I really am eager to get this figured out, so any possible help would be so much appreciated.
Thank you!