无法实例化函数无法转换类型'__NSArrayI'的值

时间:2016-10-21 22:35:00

标签: ios swift xcode

我在Swift 3中做了以下功能:

    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 = Parsexml()

        if let title = jsonElement["Title"] as? String,
            let body = jsonElement["Body"] as? String,
            let userId = jsonElement["UserId"] as? Int,
            let Id = jsonElement["Id"] as? Int
        {

            location.title = title
            location.body = body
            location.userId = userId
            location.id = Id

        }

        locations.add(location)
    }
    DispatchQueue.main.async { () -> Void in

        self.delegate.itemsDownloaded(items: locations)

    }

当我从另一个方法调用此函数时,我收到以下错误:

  

无法将'__NSArrayI'(0x105d4fc08)类型的值转换为'NSMutableArray'(0x105d4fcd0)。

它指向我这里的元素:

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

使用SIGBRT退出的地方..

我错过了什么?

2 个答案:

答案 0 :(得分:1)

您正在尝试将NSArray转换为NSMutable数组,这是警告所抱怨的内容。

获取它为您提供的数组,然后将其转换为可变数组。

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

不相关,但您可能还希望为JsonResult使用小写值以符合正常的iOS样式指南。它应该是jsonResult。

答案 1 :(得分:1)

改善代码的另一种方法:

您没有改变JsonResult,因此您无需将其声明为NSMutableArray

    var JsonResult = NSArray()

    do {
        JsonResult = try JSONSerialization.jsonObject(with: self.data as Data, options:JSONSerialization.ReadingOptions.allowFragments) as! NSArray
    } catch let error as NSError {
        print(error)
    }

以及改善代码的一些步骤......

enum MyError: Error {
    case NotArrayOfDict
}
func parseJSON() {
    do {
        guard let jsonResult = try JSONSerialization.jsonObject(with: self.data as Data) as? [[String: Any]] else {
            throw MyError.NotArrayOfDict
        }
        let locations: NSMutableArray = NSMutableArray()

        for jsonElement in jsonResult {
            let location = Parsexml()

            if let title = jsonElement["Title"] as? String,
                let body = jsonElement["Body"] as? String,
                let userId = jsonElement["UserId"] as? Int,
                let Id = jsonElement["Id"] as? Int
            {
                location.title = title
                location.body = body
                location.userId = userId
                location.id = Id

            }

            locations.add(location)
        }
        DispatchQueue.main.async { () -> Void in
            self.delegate.itemsDownloaded(items: locations)
        }
    } catch let error {
        print(error)
    }
}
  • as!施放有时会使您的应用崩溃,只有当您100%确保结果安全地转换为该类型时才使用它。如果不是,请使用带as?的guard-let更安全。

  • 尽可能使用Swift类型而不是NSSomething

  • 不需要指定.allowFragments,因为您希望将结果作为数组。

如果您可以修改代码的其他部分,则可以将代码编写为:

func parseJSON() {
    do {
        //If `self.data` was declared as `Data`, you would have no need to use `as Data`.
        guard let jsonResult = try JSONSerialization.jsonObject(with: self.data) as? [[String: Any]] else {
            throw MyError.NotArrayOfDict
        }
        var locations: [Parsexml] = [] //<-Use Swift Array

        for jsonElement in jsonResult {
            let location = Parsexml()

            if let title = jsonElement["Title"] as? String,
                let body = jsonElement["Body"] as? String,
                let userId = jsonElement["UserId"] as? Int,
                let Id = jsonElement["Id"] as? Int
            {

                location.title = title
                location.body = body
                location.userId = userId
                location.id = Id

            }

            locations.append(location)
        }
        DispatchQueue.main.async { () -> Void in
            self.delegate.itemsDownloaded(items: locations)
        }
    } catch let error {
        print(error)
    }
}