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)

}

次に、プロトコルで宣言された 2 つのメソッドのデフォルトの実装を持つプロトコル拡張があり、以下に示すように、メソッドの 1 つが他のメソッドを呼び出しています。

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)

    }



}

ここで何が起こっているのかを把握するために、数時間にわたって多くの読み物をしました。私が理解していることから、プロトコル拡張にデフォルトの実装があるため、クラスでこれら 2 つのメソッドを定義する必要はありません。私はパブリック/内部タイプの問題に出くわしましたが、他の誰かがここ StackExchange で拡張機能を使用していました (パブリックとそうでないもののラベル付けでわかるように) が、それは役に立たなかったようです私の場合。エラーを解消する唯一の方法は、元のプロトコル宣言でこれらのメソッド宣言をコメントアウトすることです。これは、クラス、プロトコル、または何かが何らかの理由で拡張機能を認識していないことを示しているようですが、コマンドをクリックするとfetchクラス宣言でメソッド呼び出しを行うと、拡張でその定義に移動します。私は解決策を見つけることができませんでした、またはこれと同じようなことをしている人でさえ、同じ問題を抱えているように見える Treehouse に何人かの人々がいます.

また、教師のコードをダウンロードして Swift 3 に変換しましたが、同じエラーが発生していたので、彼がビデオを作成したときに使用したものとは異なるバージョンの Xcode を使用していることに問題があるのでしょうか?

少しストローをつかんでいるような気がしますが、これを理解したいと思っているので、可能な限り助けていただければ幸いです。

ありがとうございました!

4

1 に答える 1

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

JSONTask を返すには、JSONTaskWithRequest が必要です。たぶん、ダウンキャストする必要がありますtask:

return task as! JSONTask

JSONTaskCompletion や JSONDecodable などが Swift で認識されないため、提供されたコードを使用できませんでした。サードパーティの JSON swift ライブラリを使用していますか?

于 2016-10-07T07:55:57.877 に答える