2016-10-07 11 views
0

私は現在、彼が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) 

    } 



} 

ここで何が起こっているのか把握しようと、何時間も読んだことがあります。私が理解しているところでは、プロトコル拡張でデフォルトの実装があるので、私のクラスでこれら2つのメソッドを定義する必要はありません。私は公共/内部型の問題に遭遇しました。他の誰かがStackExchangeでエクステンションを持っていたのです(あなたが私のものを公開しているのと同じではないと思いますが)私の場合。エラーを取り除くための唯一の方法は、元のプロトコル宣言のメソッド宣言をコメントアウトすることです。どのクラスやプロトコル、何かが何らかの理由で拡張機能を見ていないことを私に示しているようですが、私がクラス宣言のfetchメソッド呼び出しをクリックすると、それは拡張の中にある。私は解決策、あるいはこのようなことをしている人さえ見つけられませんでしたが、同じ問題を抱えているようなTreehouseにはいくつかの人がいます。

また、教師コードをダウンロードしてSwift 3に変換したところ、同じエラーが発生していたため、ビデオを作成したときのXcodeのバージョン?

私はストローでちょっと握っているような気がしますが、実際にはこれを理解してもらいたいと思っています。

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

+1

Xcodeの「レポートナビゲータ」には完全なコンパイラログがあり、コンパイラがクラスがプロトコルに準拠していないと考える理由についての詳細情報が含まれているはずです。 –

+0

ありがとう、これは何が起こっていたか把握するのを助けた。どうやら、クロージャーをエクステンションの@エスケープとしてマークすると、プロトコル宣言の中でそのようにマークされなければなりません。それを考えた上で意味がありますが、私はまだその概念を初めて習得しています。 – 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機能の実装では、あなたが持っている:JSONTaskWithRequestはJSONTaskを返すように要求され

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

。たぶん、あなたはtaskをダウンキャストする必要があります。

return task as! JSONTask 

JSONTaskCompletionとJSONDecodableのようなものがスウィフトによって認識されていないので、私はあなたの提供されたコードを使用することができませんでした。サードパーティのJSON swiftライブラリを使用していますか?

+1

さて、私はちょっと遊んで、そこに何かを見つけることができるかどうか見てみましょう。 問題が1マイルにならないようにするために除外したコードがいくつかあります。 JSONTaskCompletion、JSONTask、およびJSONはすべてタイプリアリアスです(JSONTask型は実際にはURLSessionDataTaskなので、戻すタスクはJSONTaskを返すのと同じです)。 JSONDecodableは、JSONデータのオプション辞書を定義する別のプロトコルです。 返信いただきありがとうございます! – bshock84

+1

よろしくお願いします。私はそれを考え出した!したがって、クロージャを拡張で '@エスケープする 'とマークすると、それはプロトコル宣言でそのようにマークされなければなりません。そんなに些細なことが私にそれほど多くの時間を費やさせたとは信じられない。それは私が推測する意味がありますが、私はまだエスケープ/非エスケープなものに新しいです。 – bshock84

関連する問題