【问题标题】:JSONserialization errorJSON序列化错误
【发布时间】:2017-02-11 22:02:59
【问题描述】:

我正在从生成 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 解决方案,但是,我使用 self.delegate.itemsDownloaded(locations as NSArray) 而不是 self.delegate.itemsDownloaded(locations)。

但是,所有 jsonElements 现在都为零。它在数组中获得正确数量的元素,但如果我打印它,所有值都是 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",
"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

不知道出了什么问题。有什么建议吗?

【问题讨论】:

  • 你能显示你的崩溃日志吗?
  • jsonResult = 试试 JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSMutableArray 将此行更改为 jsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as? NSMutableArray 将工作
  • 简单的建议。 不要 - 永远 - 在 Swift 中使用 NSMutable... 集合类型。它们与 Swift 集合类型无关,会导致所有问题。
  • 您的新问题似乎与原来的问题完全不同,因此您最好开始一个新线程。无论如何,结果取决于转换为LocationModel数组之前的JSON文本,您应该显示原始JSON文本(至少包含一个完整元素)。
  • 谢谢!我在这个帖子里问过这个问题:stackoverflow.com/questions/42177591/…

标签: ios json swift


【解决方案1】:

请允许我重复我的评论:

不要 - 永远 - 在 Swift 中使用 NSMutable... 集合类型。

它们与 Swift 集合类型无关,会导致所有问题。 var 关键字使任何 Swift 对象都是可变的,非常易于使用。除此之外,接收到的数组在您的代码中根本没有发生变化。

遗憾的是,建议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] 并去掉 all 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 函数中,可以使用[LocationModel],而不是使用NSMutableArray。这样我们就可以使用json.flatMap { LocationModel(json: $0) }直接flatMap json元素数组([[String:Any]])到[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)
        }
    }
    

    【讨论】:

      【解决方案3】:

      对您的问题至关重要的是该行中的 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)
      
          }
      

      我建议您使用 Swift 类型,例如 DataArrayDictionary,而不是 NSDataNSArray (NSMutableArray) 或 NSDictionary。但这对您的情况并不重要。

      【讨论】:

      • 谢谢。这修复了此时的错误。我想我在 json 数组中有一个空元素,我认为这会引发更多错误。 json 数组非常大,因此不太容易检查。但是感谢您的帮助!
      • @user1378824,我明白了。希望您能尽快解决您的问题,或者我们可以帮助您解决问题。
      猜你喜欢
      • 2015-02-07
      • 2018-07-28
      • 2018-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多