2017-02-11 81 views
0

我從一個生成json數組的php腳本中提取數據。 iOS更新後,我的jsonserialization崩潰了應用程序。根據jsonformatter.org和freeformatter.com/json-validator.html(符合RFC4627),json應該很好地形成。 這是代碼。任何幫助是極大的讚賞!JSON序列化錯誤

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). 

UPDATE 我現在用vadians解決方案,但是,而不是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 

不知道什麼錯誤。有什麼建議麼?

+2

你可以顯示你的崩潰日誌嗎? –

+0

jsonResult =嘗試JSONSerialization.jsonObject(使用:self.data作爲數據,選項:JSONSerialization.ReadingOptions.allowFragments)as! NSMutableArray將此行更改爲jsonResult = try JSONSerialization.jsonObject(with:self.data as Data,options:JSONSerialization.ReadingOptions.allowFragments)as? NSMutableArray將工作 –

+2

簡單的建議。 **不要 - 永遠不要在Swift中使用'NSMutable ...'集合類型**。它們與Swift收集類型無關並導致您的所有問題。 – vadian

回答

1

什麼是你的問題的關鍵是這一部分as! NSMutableArray在該行:

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

即使在較老的iOS的,轉換的NSJSONSerialization.JSONObjectWithDataNSMutableArray結果不保證操作(當你不指定.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) 

    } 

我建議你使用斯威夫特類型,如DataArrayDictionary,而不是NSDataNSArrayNSMutableArray)或NSDictionary。但這對你的情況並不重要。

+0

謝謝。這點解決了這個錯誤。我認爲我在json數組中有一個空元素,我認爲這會導致更多的錯誤。 json數組非常大,所以不容易檢查。但感謝您的幫助! – user1378824

+0

@ user1378824,我明白了。希望你能儘快解決你的問題,或者我們可以幫助你解決你的問題。 – OOPer

3

請讓我重複我的評論:

不 - 從來沒有 - 斯威夫特用NSMutable...集合類型。

它們與Swift集合類型無關並導致所有問題。 var關鍵字使得任何Swift對象都是可變的,非常容易使用。除此之外,收到的數組在您的代碼中完全沒有發生變異。

不幸的半知識教程這表明NSMutable...永遠不會死關:/

在夫特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],擺脫所有as? String轉換。

2

我建議創建一個可選的init方法,它需要json並嘗試創建一個LocationModel

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]])到[LocationModel]的數組flatMap

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) 
    } 
}