Got a error on (Xcode6 BETA 6) if a try to get an object of string:
let jsonString : String = "[{\"name\":[\"Fred\",\"John\"],\"age\":21},{\"name\":\"Bob\",\"age\":35}]"
let myData:NSData? = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
var jsonResult:NSArray = NSJSONSerialization.JSONObjectWithData(myData!, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSArray
println(jsonResult.objectAtIndex(0).objectForKey("name").objectAtIndex(0))
print never get called, cause the error. Anyone a idea?
Getting value from NSDictionary or NSArray return AnyObject object. So you should type cast to appropriate type. Try this
println(((jsonResult.objectAtIndex(0) as NSDictionary).objectForKey("name") as NSArray).objectAtIndex(0))
Another option would be to cast jsonResult to an Array<AnyObject> and use subscript syntax to get necessary value
let jsonString : String = "[{\"name\":[\"Fred\",\"John\"],\"age\":21},{\"name\":\"Bob\",\"age\":35}]"
let myData:NSData? = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
var jsonResult: AnyObject = NSJSONSerialization.JSONObjectWithData(myData!, options: NSJSONReadingOptions.MutableContainers, error: nil);
if let lJsonArray = jsonResult as? Array<AnyObject> {
println(lJsonArray[0].objectForKey("name")[0])
}
I would suggest creating one or more classes and deserializing that JSON, to better access to the data and avoiding mistakes when accessing.
By the way by making data types more explicit it works:
let dict = jsonResult.objectAtIndex(0) as NSDictionary
let array = dict["name"] as NSArray
println(array.objectAtIndex(0))
Related
I have this code
let jsonData = try JSONSerialization.jsonObject(with: data, options: []) as! [Any?]
if var first = jsonData[0] as! String?{
if(first=="Error"){
DispatchQueue.main.async(execute: {
self.postNotFoundLabel.isHidden = false
});
}else if(first=="Empty"){
print("Empty")
}
}
What i want to do is to cast jsonData[0] to String if it's possible and if it's not then move on.But instead when it's not possible application stops and gives me an error
Could not cast value of type '__NSDictionaryI' (0x1092054d8) to 'NSString' (0x108644508).
How can i cast only when it's possible?
You are trying to force-cast to an optional String. That's not what you want.
Change:
if var first = jsonData[0] as! String? {
to:
if var first = jsonData[0] as? String {
This tries to cast to String. If jsonData[0] isn't actually a String, you get nil and the if var fails.
And you probably want if let, not if var since you don't seem to be making any change to first.
First of all JSON objects will never return optional values so [Any?] is nonsense.
Second of all the error message says the type cast to string is inappropriate because the type of the result is actually a dictionary.
Solution: Check the type for both String and Dictionary
if let jsonData = try JSONSerialization.jsonObject(with: data) as? [Any],
let first = jsonData.first {
if let firstIsDictionary = first as? [String:Any] {
// handle case dictionary
} else if let firstIsString = first as? String {
// handle case string
}
}
PS: A type cast forced unwrap optional to optional (as! String?) is nonsense, too.
Here's the Swifty way to do what you're doing :)
guard let jsonData = try JSONSerialization.jsonObject(with: data, options: []) as? [Any?], let first = jsonData[0] as? String else {
DispatchQueue.main.async(execute: {
self.postNotFoundLabel.isHidden = false
});
return
}
if(first == "Empty") {
print(first)
}
Don't use as! if you are not sure that casting will succeed. The exclamation mark after the as keyword forces the casting, which throws an error if the casting does not succeed.
Use as? instead, which returns an optional variable of the type you were trying to casting to. If the casting fails, instead of throwing an error, it just returns nil.
let jsonData = try JSONSerialization.jsonObject(with: data) as? [Any]
if var first = jsonData.first as? String{
if(first=="Error"){
DispatchQueue.main.async(execute: {
self.postNotFoundLabel.isHidden = false
});
}else if(first=="Empty"){
print("Empty")
}
}
I am fairly new to the Swift syntax and am receiving this error with my code "Cannot assign through subscript: subscript is get only"
This is from the line: friendDictionary[(friendUID as? String)!] = ["name": friendsData!["name"]]
Any advice on the correct way of doing it would be very helpful.
func getFriendsUIDs() {
if FBSDKAccessToken.currentAccessToken() == nil {
print("failed to start graph request")
return
}else{
}
if FBSDKAccessToken.currentAccessToken() != nil {
}
let parameters = ["fields": "name, id, picture"]
FBSDKGraphRequest(graphPath: "/me/friends", parameters: parameters).startWithCompletionHandler {
(NSURLConnection, result, requestError) in
let friendIds = result["id"] as? NSDictionary
let friendsData = friendIds!["data"] as? [NSDictionary]
var ref: FIRDatabaseReference!
ref = FIRDatabase.database().reference()
ref.child("users").child((FIRAuth.auth()?.currentUser?.uid)!).child("friendUIDs").observeEventType(.Value, withBlock: { (snapshot) in
self.FriendUIDs = NSArray()
self.FriendUIDs = (snapshot.value as? NSArray)!
print(self.FriendUIDs)
var friendDictionary = NSDictionary()
for friendUID in self.FriendUIDs {
friendDictionary[(friendUID as? String)!] = ["name": friendsData!["name"]]
}
self.fetchFriendFeed(friendDictionary)
}) { (error) in
print(error.localizedDescription)
}
}
}
func fetchFriendFeed(friendDictionary: NSDictionary) {
var ref: FIRDatabaseReference!
ref = FIRDatabase.database().reference()
for friendUID in FriendUIDs {
ref.child("users").child(friendUID as! String).child("Agenda").observeEventType(.ChildAdded, withBlock: { (snapshot) in
print(snapshot)
if let dictionary = snapshot.value as? [String: AnyObject] {
let friendPost = FriendPost()
friendPost.picture = friendDictionary[friendUID as! String]? ["picture"] as? String
friendPost.activity = dictionary["activity"] as? String
friendPost.date = dictionary["date"] as? String
friendPost.time = dictionary["time"] as? String
friendPost.friendname = friendDictionary[friendUID as! String]? ["name"] as? String
self.friendPosts.append(friendPost)
dispatch_async(dispatch_get_main_queue(), {
self.collectionView?.reloadData()
Nothing to do with Swift. You've elected to use Objective-C, in effect, by making friendDictionary an NSDictionary. NSDictionary is immutable; you can't assign into it or alter it in any way. That is simply a fact about Objective-C. The Swift var declaration makes no difference to this fact.
A better choice, since you are writing in Swift, would be to use a Swift dictionary, which is [AnyHashable:Any]() (in Swift 3). This will interchange with NSDictionary when you are talking to Objective-C, but it will give you a mutable dictionary because you (rightly) declared it with var.
Have you tried using NSMutableDictionary? That solved the issue for me.
For those who get stuck here, another reason for this happens when you try to assign something that does not conform the actual dictionary, in my example i was doing something like this:
var dict = [Date : UUID]()
let randomUUID = UUID()
dict[randomUUID] = Date.now
whereas I meant to write UUID : Date but I was sleepy so i made a mistake, and Swift gave me a misleading error saying subscript is get-only. So this error also appears with type mismatch for Swift 5.7.
I have some code to get EXIF data from file, but it uses NS-Types. I like to get Swift 3 conform and use standard swift types like Dictionary or String. When deleting "NS", I get the error that ".value()" does not exist. And no hint by the compiler what is the new function call:
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)! as NSDictionary
let exifDict = imageProperties.value(forKey: "{Exif}") as! NSDictionary
let dateTimeOriginal = exifDict.value(forKey: "DateTimeOriginal") as! NSString
print ("DateTimeOriginal: \(dateTimeOriginal)")
let PixelXDimension = exifDict.value(forKey: "PixelXDimension") as! Double
print ("PixelXDimension: \(PixelXDimension)")
let exifDictTIFF = imageProperties.value(forKey: "{TIFF}") as! NSDictionary
// optional
if let Software = exifDictTIFF.value(forKey: "Software") as? NSString {
print ("Software: \(Software)")
}
Any hint how to change it?
Additionally:
Using this
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil)! as Dictionary
let exifDict = imageProperties["{Exif}"] as! Dictionary
will deliver an error "Ambiguous reference to member 'subScript'" for the second row!
All of the NSDictionary needs to be something like [String:Any]. And all of the value calls should use normal key access.
let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil)
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource!, 0, nil) as! [String:Any]
let exifDict = imageProperties["{Exif}"] as! [String:Any]
let dateTimeOriginal = exifDict["DateTimeOriginal"] as! String
print ("DateTimeOriginal: \(dateTimeOriginal)")
let PixelXDimension = exifDict["PixelXDimension"] as! Double
print ("PixelXDimension: \(PixelXDimension)")
let exifDictTIFF = imageProperties["{TIFF}"] as! [String:Any]
// optional
if let Software = exifDictTIFF["Software"] as? String {
print ("Software: \(Software)")
}
This code is terrible. All of those uses of ! are a bad idea. Proper, safe unwrapping and casting should be used throughout this code.
When I try to remove a core data entry from my project, I bump into the error
cannot invoke 'deleteObject' with an argument list of '([AnyObject]?)'
I think this basically asking me to cast the object but when I try this, I get the same error. My code is as follows:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = appDelegate.managedObjectContext
var error:NSError? = nil
let request = NSFetchRequest(entityName: projectEntityName)
let pred = NSPredicate(format: "projectName = %#", projectName)
request.predicate = pred
let objects = context?.executeFetchRequest(request, error: &error)
if let objectList = objects {
for thisProject in objectList {
thisProject.deleteObject(objects)
}
}
appDelegate.saveContext()
Can anyone help with this?
You have your variables mixed up. deleteObject is a method of the NSManagedObjectContext, and you pass the object to be deleted as the parameter:
if let objectList = objects {
for thisProject in objectList {
context!.deleteObject(thisProject)
}
}
Use as.
thisProject.deleteObject(objects as! [type])
First of all, I tried using JSON Serialization in the following code and I tried looping through each items available in the array. However, it must be type casting that I am missing something. Here is the snippet of what I am trying to do:
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options:
NSJSONReadingOptions.MutableContainers, error: nil) as
NSDictionary
var items = [[String:String]()]
var item: AnyObject
var authorDictionary: AnyObject
for var i = 0; i < jsonResult["items"].count; i++ {
items.append([String:String]())
items[i]["content"] = item["content"] as? NSString
items[i]["title"] = item["title"] as? NSString
items[i]["publishedDate"] = item["published"] as? NSString
authorDictionary = item["author"] as NSDictionary
items[i]["author"] = item["displayName"] as? NSString
}
To resolve your error, change this:
jsonResult["items"]
to this:
(jsonResult["items"] as! NSArray)
Sorry, i am not with my xcode here, but looking the code i think in something about this.
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options:
NSJSONReadingOptions.MutableContainers, error: nil) as
NSDictionary
var items = [[String:String]()]
var item: AnyObject
var authorDictionary: AnyObject
if let itemsFromJson:NSArray = jsonResult["items"] as? NSArray
{
for itemJson in itemsFromJson {
items.append([String:String]())
items[i]["content"] = itemJson["content"] as? NSString
items[i]["title"] = itemJson["title"] as? NSString
items[i]["publishedDate"] = itemJson["published"] as? NSString
authorDictionary = itemJson["author"] as NSDictionary
items[i]["author"] = itemJson["displayName"] as? NSString
}
}