JSON序列化错误

我从一个生成json数组的php脚本中提取数据。 iOS更新后,我的jsonserialization崩溃的应用程序。 json应该根据jsonformatter.org和freeformatter.com/json-validator.html(符合RFC4627)进行良好的组织。 这是代码。 任何帮助是极大的赞赏!

func parseJSON() { var jsonResult: NSMutableArray = NSMutableArray() do{ jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSMutableArray } catch let error as NSError { print(error) } var jsonElement: NSDictionary = NSDictionary() let locations: NSMutableArray = NSMutableArray() for i in 0 ..< jsonResult.count { jsonElement = jsonResult[i] as! NSDictionary let location = LocationModel() //the following insures none of the JsonElement values are nil through optional binding if let id = jsonElement["id"] as? String, let oprettelsesdato = jsonElement["oprettelsesdato"] as? String, let overskrift = jsonElement["overskrift"] as? String, let address = jsonElement["address"] as? String, let intro = jsonElement["intro"] as? String, let email = jsonElement["email"] as? String, let tlf = jsonElement["tlf"] as? String, let annonce = jsonElement["annonce"] as? String, let journalnr = jsonElement["journal"] as? String { location.id = id location.oprettelsesdato = oprettelsesdato location.overskrift = overskrift location.address = address location.intro = intro location.email = email location.tlf = tlf location.annonce = annonce location.journalnr = journalnr } locations.add(location) } DispatchQueue.main.async(execute: { () -> Void in //print("Check home") self.delegate.itemsDownloaded(locations) }) } 

系统崩溃日志:

 objc[1285]: Class PLBuildVersion is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/AssetsLibraryServices.framework/AssetsLibraryServices (0x11799a998) and /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/System/Library/PrivateFrameworks/PhotoLibraryServices.framework/PhotoLibraryServices (0x1177bc880). One of the two will be used. Which one is undefined. Could not cast value of type '__NSArrayI' (0x105f1ed88) to 'NSMutableArray' (0x105f1ee50). 

更新我现在使用vadians解决scheme,但是,而不是self.delegate.itemsDownloaded(地点),我使用self.delegate.itemsDownloaded(地点作为NSArray)。

但是,所有jsonElements现在都是零。 它获得数组中正确数量的元素,但如果我打印它的所有值是零:

 ( "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil", "id: nil, oprettelsesdato: nil, overskrift: nil, address: nil, journalnr: nil" ) 

这里是我尝试检索数据的地方。

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let item: LocationModel = feedItems[indexPath.row] as! LocationModel let cellIdentifier: String = "BasicCell" let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)! //myCell.detailTextLabel!.text = item.oprettelsesdato myCell.textLabel!.text = item.overskrift myCell.textLabel!.leadingAnchor.constraint(equalTo: myCell.leadingAnchor).isActive = true myCell.textLabel!.topAnchor.constraint(equalTo: myCell.topAnchor).isActive = true myCell.textLabel!.heightAnchor.constraint(equalTo: myCell.heightAnchor, multiplier: 1.0).isActive = true myCell.textLabel!.widthAnchor.constraint(equalTo: myCell.heightAnchor, multiplier: 0.8).isActive = true //print(item.id) <-returns nil //print(item.oprettelsesdato) <-returns nil //print(item.overskrift) <-returns nil extralabel!.text = item.oprettelsesdato // <-This is where the error is thrown extralabel!.textColor = UIColor.white myCell.contentView.addSubview(extralabel!) //some more stuff... } 

错误:

 fatal error: unexpectedly found nil while unwrapping an Optional value 

不知道发生了什么问题。 有什么build议么?

对于你的问题至关重要的是这个部分as! NSMutableArray as! NSMutableArray

 jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSMutableArray 

即使在较老的iOS中,将NSJSONSerialization.JSONObjectWithData的结果转换为NSMutableArray也不是保证操作 (当您不指定.mutableContainers选项时)。

看到你的整个代码,你不会突变jsonResult ,所以你可以使用一个简单的NSArray而不是NSMutableArray

  var jsonResult: NSArray = NSArray() do{ jsonResult = try JSONSerialization.jsonObject(with: self.data as Data) as! NSArray } catch let error as NSError { print(error) } 

我build议你使用Swifttypes,比如DataArray或者Dictionary ,而不是NSDataNSArrayNSMutableArray )或者NSDictionary 。 但是这对你来说并不重要。

请让我重复一下我的评论:

不要 – 永远不要 – 在Swift中使用NSMutable...集合types。

它们与Swift收集types无关,并导致所有问题。 var关键字使得任何Swift对象都是可变的,非常容易使用。 除此之外,接收的数组在您的代码中完全没有发生变异。

可悲的是,build议NSMutable...一半知识教程永远不会消失:

在Swift 3

  • 一个JSON字典是[String:Any]
  • 一个JSON数组是[[String:Any]][Any]

由于JSON对象应该是一个数组.allowframents是相当无用的。

所以:

 func parseJSON() { var jsonResult = [[String:Any]]() do{ jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:[]) as! [[String:Any]] } catch { print(error) return } var locations = [LocationModel]() for jsonElement in jsonResult { // no ugly C-style index based loops! let location = LocationModel() //the following insures none of the JsonElement values are nil through optional binding if let id = jsonElement["id"] as? String, let oprettelsesdato = jsonElement["oprettelsesdato"] as? String, let overskrift = jsonElement["overskrift"] as? String, let address = jsonElement["address"] as? String, let intro = jsonElement["intro"] as? String, let email = jsonElement["email"] as? String, let tlf = jsonElement["tlf"] as? String, let annonce = jsonElement["annonce"] as? String, let journalnr = jsonElement["journal"] as? String { location.id = id location.oprettelsesdato = oprettelsesdato location.overskrift = overskrift location.address = address location.intro = intro location.email = email location.tlf = tlf location.annonce = annonce location.journalnr = journalnr } locations.append(location) } DispatchQueue.main.async { //print("Check home") self.delegate.itemsDownloaded(locations) } } 

注意:如果jsonElement只包含string,你甚至可以将字典转换为[String:String]并将其全部清除 as? String as? String转换。

我build议创build一个可选的init方法,它接受json并尝试创buildLocationModel

 struct LocationModel { var id: String var oprettelsesdato: String var overskrift: String var address: String var intro: String var email: String var tlf: String var annonce: String var journalnr: String init?(json: [String:Any]) { guard let id = json["id"] as? String, let oprettelsesdato = json["oprettelsesdato"] as? String, let overskrift = json["overskrift"] as? String, let address = json["address"] as? String, let intro = json["intro"] as? String, let email = json["email"] as? String, let tlf = json["tlf"] as? String, let annonce = json["annonce"] as? String, let journalnr = json["journal"] as? String else { return } self.id = id self.oprettelsesdato = oprettelsesdato self.overskrift = overskrift self.address = address self.intro = intro self.email = email self.tlf = tlf self.annonce = annonce self.journalnr = journalnr } } 

然后,在parseJSON函数中,而不是使用NSMutableArray ,可以使用[LocationModel] 。 这样,我们可以使用json.flatMap { LocationModel(json: $0) }将json元素数组( [[String:Any]] )直接json.flatMap { LocationModel(json: $0) }[LocationModel]

 func parseJSON() { var locations = [LocationModel]() do{ if let json = try JSONSerialization.jsonObject(with: data as Data, options: []) as? [[String:Any]] { locations = json.flatMap { LocationModel(json: $0) } } } catch let error as NSError { print(error) } DispatchQueue.main.async { self.delegate.itemsDownloaded(locations) } }