1

我目前正在学习 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 版本不同的问题?

我觉得我有点抓住稻草了,但我真的很想弄清楚这一点,所以任何可能的帮助都会非常感激。

谢谢!

4

1 回答 1

1

我使用 Xcode 的 Playground 来测试和玩弄你的代码。我采用了您的代码(协议声明、协议扩展和类声明)并大大简化了JSONTaskWithRequest()andfetch()函数。编译的代码没有“不符合错误”。这是我使用的代码:

//: 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 库吗?

于 2016-10-07T07:55:57.877 回答