1

私は C# 開発者で、Swift tvO に変換し、学習を始めたばかりです。ある程度の進歩はありましたが、json へのネストされた呼び出しを処理する方法がわかりません。ソースはさまざまなプロバイダーからのものであるため、クエリを組み合わせることはできません。

TVSeries に poster_path があるように、内部要求が完了するのを待つにはどうすればよいですか? ショーをコレクションに追加してから、ポスター パスの読み込みを別のスレッドで処理して、UI エクスペリエンスを遅らせないようにするより良い方法はありますか?

    func downloadTVData() {
    let url_BTV = NSURL(string: BTV_URL_BASE)!
    let request_BTV = NSURLRequest(URL: url_BTV)
    let session_BTV = NSURLSession.sharedSession()

    //get series data
    let task_BTR = session_BTV.dataTaskWithRequest(request_BTV) { (data_BTV, response_BTV, error_BTV) -> Void in
        if error_BTV != nil {
            print (error_BTV?.description)
        } else {
            do {
                let dict_BTV = try NSJSONSerialization.JSONObjectWithData(data_BTV!, options: .AllowFragments) as? Dictionary<String, AnyObject>
                if let results_BTV = dict_BTV!["results"] as? [Dictionary<String, AnyObject>]{
                    for obj_BTV in results_BTV {
                        let tvshow = TVSeries(tvDict: obj_BTV)
                        //for each tv series try to load a poster_path from secondary provider
                        if let str = obj_BTV["title"] as? String!{
                            let escapedString = str?.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())!

                            if let url = NSURL(string: self.SEARCH_URL_BASE + escapedString!) {
                                let request = NSURLRequest(URL: url)
                                let session = NSURLSession.sharedSession()
                                let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
                                    if error != nil {
                                        print (error?.description)
                                    } else {
                                        do {
                                            let dict = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments) as? Dictionary<String, AnyObject>

                                            if let results = dict!["results"] as? [Dictionary<String, AnyObject>] {

                                                //iterate through the poster array
                                                for obj in results {
                                                    if let path = obj["poster_path"] as? String {
                                                        tvshow.posterPath = path
                                                        break
                                                    }
                                                }
                                            }
                                        } catch let error as NSError {
                                            print(error.description)
                                        }
                                    }
                                }
                                task.resume()
                            }
                        }
                        self.tvSeries.append(tvshow)
                    }
                    dispatch_async(dispatch_get_main_queue()){
                        self.collectionView.reloadData()
                    }
                }
            }  catch let error as NSError {
                print(error.description)
            }
        }
    }
    task_BTR.resume()
}

ご協力いただきありがとうございます!

4

1 に答える 1

1

複数のメソッドに分割し、コールバックで操作をシーケンス化し、Swift の組み込みthrowsエラー処理メカニズムを利用することをお勧めします。完璧ではありませんが、出発点として役立つかもしれない例を次に示します。

class TVSeries
{
    let title: String
    var posterPath: String?

    enum Error: ErrorType {
        case MalformedJSON
    }

    init(tvDict: [String: AnyObject]) throws
    {
        guard let title = tvDict["title"] as? String else {
            throw Error.MalformedJSON
        }

        self.title = title
    }

    static func loadAllSeries(completionHandler: [TVSeries]? -> Void)
    {
        NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: BTV_URL_BASE)!) { data, response, error in
            guard let data = data else {
                print(error)
                completionHandler(nil)
                return
            }

            do {
                completionHandler(try fromJSONData(data))
            }
            catch let error {
                print(error)
            }
        }.resume()
    }

    static func fromJSONData(jsonData: NSData) throws -> [TVSeries]
    {
        guard let dict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: .AllowFragments) as? [String: AnyObject] else {
            throw Error.MalformedJSON
        }

        guard let results = dict["results"] as? [[String: AnyObject]] else {
            throw Error.MalformedJSON
        }

        return try results.map {
            return try TVSeries(tvDict: $0)
        }
    }

    func loadPosterPath(completionHandler: () -> Void)
    {
        guard let searchPath = title.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet()) else {
            completionHandler()
            return
        }

        let url = NSURL(string: SEARCH_URL_BASE)!.URLByAppendingPathComponent(searchPath)
        NSURLSession.sharedSession().dataTaskWithURL(url) { [weak self] data, response, error in
            defer { completionHandler() }

            guard let strongSelf = self else { return }

            guard let data = data else {
                print(error)
                return
            }

            do {
                strongSelf.posterPath = try TVSeries.posterPathFromJSONData(data)
            }
            catch let error {
                print(error)
            }
        }.resume()
    }

    static func posterPathFromJSONData(jsonData: NSData) throws -> String?
    {
        guard let dict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: .AllowFragments) as? [String: AnyObject] else {
            throw Error.MalformedJSON
        }

        guard let results = dict["results"] as? [[String: AnyObject]] else {
            throw Error.MalformedJSON
        }

        for result in results {
            if let path = result["poster_path"] as? String {
                return path
            }
        }

        return nil
    }
}

RxSwiftAlamofireのようなものを調べるのも時間の価値があるかもしれません。これらは、この種のデータ変換/シーケンス操作に役立ちます。

于 2016-01-06T05:07:44.457 に答える