我目前正在通过Treehouse 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
方法调用,它带我到扩展中的定义。我还没有找到解决方案,甚至是那些做类似事情的人,Treehouse上有几个人似乎也有同样的问题。
另外,我下载了教师代码,并将其转换为Swift 3,并且它也得到了同样的错误,所以也许是因为他使用了不同版本的Xcode时遇到的问题制作了视频?
我觉得我有点抓住吸管,但我真的很想把这个弄清楚,所以任何可能的帮助都会非常感激。
谢谢!
答案 0 :(得分: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和/或fetch中存在错误。我建议你隔离任一功能,找出哪一个给你错误。然后从那里调试。
另外,只是另一种怀疑。在扩展的JSONTaskWithRequest函数实现中,您有:
let task = session.dataTask(with: request) {...}
return task
JSONTaskWithRequest需要返回JSONTask。也许你需要低估task
:
return task as! JSONTask
我无法使用您提供的代码,因为Swift无法识别JSONTaskCompletion和JSONDecodable等内容。您使用的是第三方JSON swift库吗?