无法弄清楚如何在 Swift 中使用 NSURLSession 将 jsonData 加载到 NSDictionary

Posted

技术标签:

【中文标题】无法弄清楚如何在 Swift 中使用 NSURLSession 将 jsonData 加载到 NSDictionary【英文标题】:Can't figure out how to load jsonData into an NSDictionary using NSURLSession in Swift 【发布时间】:2016-05-22 14:25:59 【问题描述】:

大家好。首先,我想告诉你,我在编程方面非常陌生。因此,如果我没有任何意义,我想先道歉。我为 ios Swift 做了一个训练营,但不包括 Rest 或解析 JSON。我现在正在尝试自学所有我能找到的教程。我知道有 Alamofire 让它变得更容易,但我想先学习如何使用 NSURLSession 来做到这一点。我找到了一个用旧版本的 Swift 编写的教程,现在我已经被困了好几天了。我已经尝试了所有可以在此处和 Google 上找到的选项。但我仍然无法理解我做错了什么。这是我的代码;在它下面我已经描述了我认为问题发生的地方。 提前感谢您的帮助。

import Foundation
import UIKit

class FlickrHelper: NSObject 

class func UrlForSearchString(searchString: String) -> String 
    let apiKey:String = "733e5b6f446812afdec3c021454dd9bb"
    let search:String = searchString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!
    return "https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=\(apiKey)&text=\(search)&per_page=20&format=json&njsoncallback=1"


class func UrlForFlickrPhoto(photo:FlickrPhoto, size:String) -> String 
    var _size = size
    if _size.isEmpty 
        _size = "m"
    
    return "http://farm.\(photo.farm).staticflickr.com/\(photo.photoID)_\(photo.secret)_\(_size).jpg"


func searchFlickrForString(searchStr:String, completion:(searchString:String!, flickrPhotos:NSMutableArray!, error:NSError!) -> ()) 

    let searchUrl:String = FlickrHelper.UrlForSearchString(searchStr)
    let queue:dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    dispatch_async(queue, 

        var error:NSError?

        let searchResultString:String! = try! String(contentsOfURL: NSURL(string: searchUrl)!, encoding: NSUTF8StringEncoding)

        if error != nil 
            completion(searchString: searchStr, flickrPhotos: nil, error: error)
         else 
            // Parse json response.

            let jsonData:NSData! = searchResultString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

            let resultDict = try? NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [String:AnyObject] as NSDictionary

            let status:String = resultDict?.objectForKey("stat") as! String

            if status == "fail" 
                let stError:NSError? = NSError(domain: "FlickrSearch", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey:(resultDict?.objectForKey("message"))!])

                completion(searchString: searchStr, flickrPhotos: nil, error: stError)
             else 
                let resultArray:NSArray = (resultDict?.objectForKey("photos")?.objectForKey("photo"))! as! NSArray

                let flickrPhotos:NSMutableArray = NSMutableArray()

                for photoObject in resultArray 
                    let photoDict:NSDictionary = photoObject as! NSDictionary

                    var flickrPhoto:FlickrPhoto = FlickrPhoto()
                    flickrPhoto.farm = photoDict.objectForKey("farm") as! Int
                    flickrPhoto.server = photoDict.objectForKey("server") as! String
                    flickrPhoto.secret = photoDict.objectForKey("secret") as! String
                    flickrPhoto.photoID = photoDict.objectForKey("id") as! String

                    let searchURL:String = FlickrHelper.UrlForFlickrPhoto(flickrPhoto, size: "m")
                    do 
                    let imageData:NSData = try NSData(contentsOfURL: NSURL(string: searchURL)!, options: NSDataReadingOptions())

                        let image:UIImage = UIImage(data:imageData)!

                        flickrPhoto.thumbnail = image

                        flickrPhotos.addObject(flickrPhoto)

                     catch 
                        print(error)
                    

                    completion(searchString: searchStr, flickrPhotos: flickrPhotos, error: nil)

                
            
        
    )
  

我收到 jsonData,但它没有将它分配给我的 resultDict。我的结果字典为零。我的项目崩溃的那一行是:

 let status:String = resultDict?.objectForKey("stat") as! String

但我猜问题出在这一行:

let resultDict = try? NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [String:AnyObject] as NSDictionary

【问题讨论】:

尽可能避免使用强制解包或隐式解包选项。基本上可以使用! 运算符。您需要实际检查强制转换是否成功,或者您可以设置自己在某个地方发生运行时崩溃。 Documentation here 非常感谢您的反馈。我实际上是想先让它工作,然后我会使用 if let 和 try,do,catch 来清理它。这将是我的下一个练习:-)。 我知道您想自己做这件事来学习。但是,一旦您尝试过,我建议您使用 SwiftlyJson 来控制 JSON 反序列化。这减少了您最终不得不做的许多可选链接。这仍然使用您所拥有的网络调用等,它只是使 JSON 的解析更加愉快。你可以在这里找到它:github.com/SwiftyJSON/SwiftyJSON @totiG:谢谢,你是对的。这是大多数人现在使用的 Alamofire。我期待着使用它。 as! [String:AnyObject] as NSDictionary 你为什么要这么做?如果我可以建议您调试代码的第一步:删除所有无用的操作,分析每一行并问自己它做了什么以及为什么。让事情变得更简单、更安全:使用if let 而不是!,不要两次投射同一个对象,等等。 【参考方案1】:

试试这个。

不要将空数组传递给 NSJSONSerialization.JSONObjectWithData,而是使用片段类型的允许,如下所示:

let resultDict = try? NSJSONSerialization.JSONObjectWithData(jsonData, NSJSONReadingOptions.AllowFragments)

这可能会解决问题。否则,请尝试其他一些选项。


另一种方法可能是这样。

            let json = try! NSJSONSerialization.JSONObjectWithData(json!, options: .AllowFragments)
            print("=====")
            if let item = json.objectForKey("prices") as! NSArray? 
                self.uberPriceField.text = item[0].objectForKey("estimate") as? String
            

我在自己的代码中使用了它,因为返回的 JSON 实际上只是顶层的一个数组。也许它也对你有用。

【讨论】:

谢谢,不幸的是,这也是我已经尝试过的东西:-(。 谢谢,尽管我很确定我的 JSON 是字典(它以 开头),但我确实尝试了你的建议。不幸的是,它也没有用。【参考方案2】:

以下是我在项目中使用的代码,请参考相同内容,如果问题仍然存在,请告诉我:-

 let requestURL: NSURL = NSURL(string: "(Ur URL)/get_SearchList.php?cth=\(cth),\(kwValue)")!
        let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(urlRequest) 
            (data, response, error) -> Void in

            let httpResponse = response as! NSHTTPURLResponse
            let statusCode = httpResponse.statusCode

            if (statusCode == 200) 

                do

                    let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)



                    if let products = json["product"] as? [[String: AnyObject]] 
                        dispatch_async(dispatch_get_main_queue(), 
                        for product in products 

                                if let cth = product["cth"] as? String 


                                    if let name = product["productname"] as? String 
                                        self.cthArray.append(cth);
                                        self.prodArray.append(name);


                                    

                                


                        //for loop
                            dispatch_async(dispatch_get_main_queue(),
                                self.tableView.reloadData()
                            )
                        )

                    // if loop

                
                catch
                
                    print("Error with Json: \(error)")

                

            
            else
            
                // No internet connection
                // Alert view controller
                // Alert action style default


            

        

        task.resume()

【讨论】:

以上是关于无法弄清楚如何在 Swift 中使用 NSURLSession 将 jsonData 加载到 NSDictionary的主要内容,如果未能解决你的问题,请参考以下文章

使用 swift 我无法弄清楚视频停止后如何进入新屏幕

无法弄清楚如何防止 Date 类型崩溃并在 Swift 3 中包装

Swift 3 - 无法弄清楚如何从 jsonArray 创建 json 对象

斯威夫特:无法弄清楚如何保存用户离开表格视图的方式

无法弄清楚 Swift 中 AudioQueueDispose 的用法

如何在swift 3中恢复标签可见性状态