Xcode Swift:无法将类型为 '__NSCFString' (0x102e8ac50) 的值转换为类型为 'NSDictionary' (0x102e8b8d0)

4

我正在尝试在调试区域显示我的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文件的链接

-----更新------

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个值(不知道是否应该这样显示)。当我继续执行程序到 completion(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 断点行1 断点行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中添加了回调函数后,它将从AnyObject接收数组,而不是从JsonExtrct,因此我将函数方法从func loadJns(completion: ((AnyObject) -> Void)!) {更改为func loadJns(completion: ((JsonExtrct) -> Void)!) {,现在我遇到了与JnsGridController中的错误类似的错误:Cannot invoke 'dispatch_async' with an argument list of type '(dispatch_queue_t!, () -> _)'
1个回答

7
错误很明显,你正在尝试将一个字符串转换为字典。在你发布的json中,键“image”,“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 imageURL = data["image"] as? String {
    self.imageUrl = imageURL
}

如果您不确定要转换的对象的类型,请避免使用显式解包。
更新:
新错误与先前错误性质相同,即您隐式解包了一个空值,这个空值在此处是闭包“completion”。您定义的闭包是“completion:((AnyObject) -> Void)!”告诉编译器:“当您需要使用此闭包时,请不用担心它肯定具有非空值。”
但实际上,您在此处传递了一个“nil”值:
json.loadBbup(nil)
隐式解包很有用,但您使用方法不正确。如果您希望完成闭包可以是“nil”,则必须以可选方式定义它:
completion:((AnyObject) -> Void)?
然后以以下方式调用它:
completion?(jnslst)
关于数组仅包含3个值而不是20个值的原因有很多。我建议在此行中放置断点jns1st.append(jnsExtract),并查看jnsExtract的值。
一般建议:
- 除非您确定变量具有非空值,否则避免使用隐式解包。 - 当您不需要修改变量时,请使用let而不是var; 这样,您可以确保该值永远不会更改。

谢谢您的帮助!我在我的问题底部添加了一个更新。我知道您在答案的最后一句中提到要避免显式解包,因为我的更新中可能会出现错误。我一直在阅读有关Swift的错误,因为它无法完美地编译它。您对如何解决此错误有什么建议? - wlmrlsda
再次感谢您的帮助!在结尾处完成?(jnslst)一行中,我不得不添加一个额外的?,因为如果我没有添加?!,它会给我一个错误。关于在jnslst.append(jnsextrct)中添加断点,我将会在我的问题中发布两个值截图。 - wlmrlsda
你介意我把项目发送给你,这样你可以快速浏览并帮助我理解吗? - wlmrlsda
当然,如果您知道如何做到这一点,您可以创建一个Github项目,以便更轻松地共享对该项目的修改。 - LuckyStarr
好的,当我把它放到github上时,我会告诉你。谢谢! - wlmrlsda
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接