2016-10-07 38 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

相關問題