Xcode Swift: Could not cast value of type '__NSCFString' (0x102e8ac50) to 'NSDictionary' (0x102e8b8d0)
The error is clear, you are trying to convert a string to a dictionary. In the json which you posted the key "image", "image2" and "image3" are strings.
{
"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
}
so the correct way the get those values is:
if let let imageURL = data["image"] as? String {
self.imageUrl = imageURL
}
Avoid to use the explicit unwrap if you are not sure of the type of the object that you are try to casting.
UPDATE
The new error is of the same nature of the previous one, you are implicitly unwrapping a nil value that in this case is the closure completion
. Your definition of the closure is completion: ((AnyObject) -> Void)!
say to the compiler:
Don't worry when you will need to use this closure it will certainly has a non-nil value.
But instead you are passing a nil
value here:
json.loadBbup(nil)
The implicit unwrapping is useful but you are using it in a wrong way. If you want that the completion closure can be nil
you have to define it as optional in this way:
completion: ((AnyObject) -> Void)?
and the call it in this way:
completion?(jnslst)
Regarding the fact that the array contains only 3 values instead 20 there be a lot of reasons. I suggest to put a breakpoint in this line jnslst.append(jnsextrct)
and watch the value of jnsextrct
.
As general advices:
- avoid to use the implicit unwrapping unless you're certain the variable as non-nil value.
- use let instead var when you don't need to modify a variable; in this way you are certain that value never changes.
wlmrlsda
Updated on June 04, 2022Comments
-
wlmrlsda over 1 year
I am trying to display my JSON information in the debug area but I am having a problem in which I have not found a solution.
First of all, let me display the code I have so far:
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. } }
So, when I run the app with a breakpoint in
for jnsextrct in bbupData{
in the BBUpJSON.swift file, it shows in the left side of the debug area that I have 20 values. Everytime I runpo bbupData
in the right output of the debug area it just partially shows me 3 of the values out of the 20 I have in my JSON file. When I add another breakpoint incompletion(jnslst)
located at the end of the same swift file and press Continue program execution, I get the following error:Could not cast value of type '__NSCFString' (0x10c3c2c50) to 'NSDictionary' (0x10c3c38d0)
. It then redirects the error tolet image = data["image"] as! NSDictionary
that is located in my JSONExtrct.swift.This is the link to the json file that is trying to extract the information.
-----UPDATE------
Modified the values of the strings in JSONExtrct.swift to:
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 }
And added the same breakpoints to see the results in BBUpJSON.swift. From the breakpoint
for jnsextrct in bbupData{
, it still displays me the same 3 values out of the 20 I have (don't know if that should show that way) when I typepo bbupData
in the output area. When I Continue program execution tocompletion(jnslst)
, it doesn't show me the previous error but it shows me the following output result when typingpo 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]
When I continue and add one more breakpoint at the last bracket, it shows me the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
and it redirects the error tocompletion(jnslst)
showingThread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP,subcode=0x0)
UPDATE 2
It seems that it reads just one value through
jnsextrct
and returns it tojnslst
. Then when I add the other breakpoint in the next screenshot it goes to the next value. When I typepo jnslst
in the second screenshot, it returns one[BonBonUp.JSONExtrct]
instead of 20 of them like in the previous update.UPDATE 3
Already added
CollectionView
to theMain.StoryBoard
but I am getting the following errors when I try to upload JSON information (Not images yet) to each grid. Under JnsGridController.swift, in order to receive the information from myJSON
files, I had to create a new method that would callback asdidLoadJns
. Here is the part of that code:jns = [JsonExtrct]() let json = JnsJson() json.loadJns(didLoadJns) } func didLoadJns(jns: [JsonExtrct]){ self.jns = jns collectionView.reloadData()
In
json.loadJns(didLoadJns)
,didLoadJns
use to benil
before I added thefunc
method but I am getting the following error:Cannot invoke 'loadJns' with an argument list of type '(([JsonExtrct]) -> ())'
Also in JnsJson.swift, since I added that callback function in JnsGridController its going to be receiving arrays from
JsonExtrct
instead ofAnyObject
so I changed the function method fromfunc loadJns(completion: ((AnyObject) -> Void)!) {
tofunc loadJns(completion: ((JsonExtrct) -> Void)!) {
and now I am getting a similar error as the one in JnsGridController:Cannot invoke 'dispatch_async' with an argument list of type '(dispatch_queue_t!, () -> _)'