【问题标题】:Xcode Swift: Could not cast value of type '__NSCFString' (0x102e8ac50) to 'NSDictionary' (0x102e8b8d0)Xcode Swift:无法将“__NSCFString”(0x102e8ac50)类型的值转换为“NSDictionary”(0x102e8b8d0)
【发布时间】:2015-10-26 03:29:08
【问题描述】:

我正在尝试在调试区域中显示我的 JSON 信息,但我遇到了一个我没有找到解决方案的问题。

首先,让我展示一下我目前的代码:

BBUpJSON.swift

import Foundation

class BBUpJSON {

    func loadBbup(completion: ((AnyObject) -> Void)!) {

        var urlString = "http://xxxdsgn.xxxhost.com/json/jnslst.json"

        let session = NSURLSession.sharedSession()
        let bbupUrl = NSURL(string: urlString)

        var task = session.dataTaskWithURL(bbupUrl!){
            (data, response, error) -> Void in

            if error != nil {
                println(error.localizedDescription)
            } else {

                var error : NSError?

                var bbupData = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &error) as! NSArray

                var jnslst = [JSONExtrct]()

                for jnsextrct in bbupData{
                    let jnsextrct = JSONExtrct(data: jnsextrct as! NSDictionary)
                    jnslst.append(jnsextrct)
                }

                let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
                dispatch_async(dispatch_get_global_queue(priority, 0)) {
                    dispatch_async(dispatch_get_main_queue()) {
                        completion(jnslst)
                    }
                }

            }
        }

        task.resume()
    }

}

JSONExtrct.swift

import Foundation

class JSONExtrct {

    var titulo : String!
    var imageUrl : String!
    var imageData : NSData?
    var imageUrl2 : String!
    var imageData2 : NSData?
    var imageUrl3 : String!
    var imageData3 : NSData?
    var marca : String!
    var color : String!
    var tipo : String!
    var ref : Int!

    init(data : NSDictionary) {

        self.titulo = getStringFromJSON(data, key: "titulo")

        let image = data["image"] as! NSDictionary
        self.imageUrl = getStringFromJSON(image, key: "image")

        let image2 = data["image2"] as! NSDictionary
        self.imageUrl2 = getStringFromJSON(image, key: "image2")

        let image3 = data["image3"] as! NSDictionary
        self.imageUrl3 = getStringFromJSON(image, key: "image3")

        self.marca = getStringFromJSON(data, key: "marca")

        self.color = getStringFromJSON(data, key: "color")

        self.tipo = getStringFromJSON(data, key: "tipo")

        self.ref = data["ref"] as! Int

    }

    func getStringFromJSON(data: NSDictionary, key: String) ->String{

        //let info : AnyObject? = data[key]

        if let info = data[key] as? String {
            return info
        }

        return ""

    }

}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let json = BBUpJSON()
        json.loadBbup(nil)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

因此,当我在 BBUpJSON.swift 文件的 for jnsextrct in bbupData{ 中使用断点运行应用程序时,它会在调试区域的左侧显示我有 20 个值。每次我在调试区域的右侧输出中运行po bbupData 时,它只会部分显示我的 JSON 文件中的 20 个值中的 3 个。当我在位于同一 swift 文件末尾的 completion(jnslst) 添加另一个断点并按 继续程序执行 时,我收到以下错误:Could not cast value of type '__NSCFString' (0x10c3c2c50) to 'NSDictionary' (0x10c3c38d0)。然后它将错误重定向到位于我的 JSONExtrct.swift 中的let image = data["image"] as! NSDictionary

这是试图提取信息的 json 文件的 link

--更新------

JSONExtrct.swift中的字符串值修改为:

if let imageUrl = data["image"] as? String {
            self.imageUrl = imageUrl
        }

        if let imageUrl2 = data["image2"] as? String {
            self.imageUrl2 = imageUrl2
        }

        if let imageUrl3 = data["image3"] as? String {
            self.imageUrl3 = imageUrl3
        }

并添加相同的断点以在 BBUpJSON.swift 中查看结果。从断点for jnsextrct in bbupData{ 开始,当我在输出区域中键入po bbupData 时,它仍然显示我拥有的20 个值中的3 个(不知道是否应该这样显示)。当我Continue program executioncompletion(jnslst)时,它并没有显示上一个错误,但是在输入po jnslst时它显示了以下输出结果:

(lldb) po jnslst
[BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct, BonBonUp.JSONExtrct]

当我继续并在最后一个括号中添加一个断点时,它显示以下错误:fatal error: unexpectedly found nil while unwrapping an Optional value 并将错误重定向到 completion(jnslst),显示 Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP,subcode=0x0)

更新 2

Breakpoint Line 1

Breakpoint Line 2

它似乎只通过jnsextrct 读取了一个值并将其返回给jnslst。然后,当我在下一个屏幕截图中添加另一个断点时,它会转到下一个值。当我在第二个屏幕截图中输入po jnslst 时,它返回一个[BonBonUp.JSONExtrct],而不是像之前的更新那样返回20 个。

更新 3

已经将CollectionView 添加到Main.StoryBoard,但是当我尝试将JSON 信息(还不是图像)上传到每个网格时出现以下错误。在 JnsGridController.swift 下,为了从我的 JSON 文件中接收信息,我必须创建一个新方法,该方法将回调为 didLoadJns。这是该代码的一部分:

jns = [JsonExtrct]()
        let json = JnsJson()
        json.loadJns(didLoadJns)
    }

    func didLoadJns(jns: [JsonExtrct]){
        self.jns = jns
        collectionView.reloadData()

json.loadJns(didLoadJns) 中,didLoadJns 在我添加func 方法之前曾经是nil,但我收到以下错误:Cannot invoke 'loadJns' with an argument list of type '(([JsonExtrct]) -> ())'

同样在 JnsJson.swift 中,因为我在 JnsGridController 中添加了该回调函数,它将接收来自 JsonExtrct 而不是 AnyObject 的数组,所以我更改了从func loadJns(completion: ((AnyObject) -> Void)!) {func loadJns(completion: ((JsonExtrct) -> Void)!) { 的函数方法,现在我遇到了与 JnsGridController 中的错误类似的错误:Cannot invoke 'dispatch_async' with an argument list of type '(dispatch_queue_t!, () -> _)'

【问题讨论】:

    标签: arrays json xcode swift nsdictionary


    【解决方案1】:

    错误很明显,您正在尝试将字符串转换为字典。在您发布关键“image”的 json 中,“image2”和“image3”是字符串。

    {
        "titulo": "Verox's 1002",
        "image": "http://wlodsgn.x10host.com/img/jeans/vrxjns1002/veroxjeans1002_front.jpg",
        "image2": "http://wlodsgn.x10host.com/img/jeans/vrxjns1002/veroxjeans1002_rightside.jpg",
        "image3": "http://wlodsgn.x10host.com/img/jeans/vrxjns1002/veroxjeans1002_front_b.jpg",
        "marca": "Verox",
        "color": "Azul",
        "tipo": "Jean",
        "ref": 1002
    }
    

    所以获取这些值的正确方法是:

    if let let imageURL = data["image"] as? String {
        self.imageUrl = imageURL
    }
    

    如果您不确定要转换的对象的类型,请避免使用显式展开。

    更新

    新的错误与前一个错误的性质相同,你隐式地解包一个 nil 值,在这种情况下是闭包completion。你对闭包的定义是completion: ((AnyObject) -> Void)! 对编译器说:

    不用担心什么时候需要使用这个闭包,它肯定有一个非 nil 值。

    但是你在这里传递了一个nil 值:

    json.loadBbup(nil)

    隐式展开很有用,但是您以错误的方式使用它。如果您希望完成闭包可以是nil,您必须以这种方式将其定义为可选:

    completion: ((AnyObject) -> Void)?

    并以这种方式调用它:

    completion?(jnslst)

    关于数组只包含 3 个值而不是 20 个这一事实,有很多原因。建议在jnslst.append(jnsextrct)这一行下断点,观察jnsextrct的值。

    一般建议:

    • 避免使用隐式展开,除非您确定变量为非零值。
    • 当您不需要修改变量时,请使用 let 代替 var;这样您就可以确定价值永远不会改变。

    【讨论】:

    • 感谢您的帮助!我在问题的底部添加了更新。我知道您在回答的最后一句中提到了避免显式展开,因为我最近在更新中的错误可能就是那个错误。我一直在阅读这是 swift 的错误,因为它不能完全编译它。你有什么建议去解决这个错误?
    • 再次感谢您的帮助!必须在最后的 completion?(jnslst) 行中添加一个额外的?,因为如果我没有添加?!,它会给我一个错误。关于向jnslst.append(jnsextrct) 添加断点,我将在我的问题中发布两个值的屏幕截图。
    • 是的,您需要使用问号来调用闭包,因为现在它是可选的(我更新了答案)。对于另一个问题,尝试将循环内的这个变量 jnsextrct 的名称更改为 jnsextrct2,这样它就不会与 for-each 声明中的其他变量发生冲突。这应该不是问题,但没有“眼睛”的代码很难找到错误。
    • 您介意我将项目发给您,以便您快速浏览并帮助我理解吗?
    • 当然,如果你知道怎么做,你可以创建一个 github 项目,这样更容易分享对项目的修改。
    猜你喜欢
    • 2017-07-01
    • 1970-01-01
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 2016-01-12
    • 2017-10-16
    • 1970-01-01
    相关资源
    最近更新 更多