2016-10-07 110 views
0

我目前正在通过他树方式IOS Swift当然,我们正在建设一个天气应用程序。我已经到了一个地步,我一直得到一个错误,我的课不符合我的协议,但我不明白为什么。类不符合包含默认实现的扩展名的协议

这里是我的协议声明:

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) 

} 

然后,我有一个协议扩展在那里我有我的协议中声明了两个方法的默认实现,而方法之一是调用其他方法,如你可以看到下面。

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() 
    } 
} 

然后我有我的类声明,我得到我的不符合性错误。

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) 

    } 



} 

我已经做了大量的阅读,试图弄清楚这里发生了什么。据我所知,我不需要在我的类中定义这两种方法,因为它们在协议扩展中有默认实现。我遇到了公共/内部类型和类似的问题,其他人在StackExchange上使用它们的扩展名(正如你通过我公开标记的东西所看到的那样),但这似乎没有帮助在我的情况。我能够让错误消失的唯一方法是通过在原始协议声明中注释这些方法声明。这似乎向我表明,无论是类,还是协议,或者由于某种原因都没有看到扩展名,然而,如果我在类声明中点击fetch方法调用,它会带我到它在扩展中。我一直无法找到解决方案,或者甚至有人在做这种类似的事情,但树屋中有好几个人似乎也有同样的问题。

另外,我下载了教师代码,并将其转换为Swift 3,并且它也得到了相同的错误,所以也许这是Xcode的不同版本与他制作视频时使用的问题有关的问题?

我觉得我有点抓住吸管,但我真的很渴望得到这个想法,所以任何可能的帮助将非常感激。

谢谢!

+1

Xcode中的“报告导航器”具有完整的编译器日志,其中应包含有关编译器认为您的类不符合该协议的更多详细信息。 –

+0

谢谢,这帮助我弄清楚发生了什么事情。显然,如果你在扩展中将闭包标记为@escaping,它也必须在协议声明中标记出来,在思考它之后才有意义,但我对这个概念还是一个新的东西。 – bshock84

回答

1

我使用Xcode的游乐场来测试和玩弄你的代码。我把你的代码(协议声明,协议扩展和类声明)并且严格简化了JSONTaskWithRequest()fetch()函数。代码编译时没有“不符合性错误”。下面是我使用的代码:

//: Playground :  
import UIKit 

// protocol declaration 
public protocol APIClient { 

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

    func JSONTaskWithRequest() 
    func fetch() 
} 

// protocol extension 
public extension APIClient { 
    func JSONTaskWithRequest() { 
     print("JSONTaskWithRequest here") 
    } 
    func fetch() { 
     print("fetch here") 
    } 
} 

// class declaration 
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 
    } 
} 

我怀疑存在JSONTaskWithRequest和/或获取的错误。我建议你隔离任何一个函数来找出哪一个给你的错误。然后从那里调试。

另外,只是另一个怀疑。在扩展的JSONTaskWithRequest功能的实现,您有:

let task = session.dataTask(with: request) {...} 
return task 

JSONTaskWithRequest需要返回JSONTask。也许你需要垂头丧气task

return task as! JSONTask 

我无法使用您提供的代码,因为类似的事情和JSONTaskCompletion JSONDecodable不被认可的斯威夫特。您是否使用第三方JSON快速库?

+1

好的,我会仔细研究一下,看看我能否在那里找到一些东西。 我遗漏了一些代码来避免长达一英里的问题。 JSONTaskCompletion,JSONTask和JSON都是类型,(JSONTask类型实际上是一个URLSessionDataTask,所以返回的任务与返回JSONTask相同)。 JSONDecodable是另一种为JSON数据定义可选字典的协议。 谢谢你的回复! – bshock84

+1

好的!我想到了!所以显然如果你在扩展中把一个闭包标记为'@ escaping',那么它也必须在协议声明中标记出来。哈哈,不能相信这么微不足道的事情让我花这么多时间在上面。我猜想这是有道理的,但我对逃避/不逃避的事情仍然陌生。 – bshock84

相关问题