Swift - extract data from dictionary - ios

I have custom object, that contains json. If I print it, it looks like
{
"first_name" = Name;
id = 111111;
"last_name" = LastName;
"photo_100" = "https://url.jpg";
}
This object has property .json. To extract data from it in objective-C I use
NSLog(#"id%#", [[response.json firstObject] objectForKey:#"id"]);
But in Swift, if I try
var dict = response.json
self.name = dict.firstObject.objectForKey("first_name")
self.lastName = dict.firstObject.objectForKey("last_name")
self.photoUrl = dict.firstObject.objectForKey("photo_100")
I get compile or runtime error. I tried call firstObject in dict declaration and and tried downcasting to string - everything leads to errors.
How to extract data correctly ?
UPD: object definition
#interface VKResponse : VKObject
/// Request which caused response
#property(nonatomic, weak) VKRequest *request;
/// Json content of response. Can be array or object.
#property(nonatomic, strong) id json;
/// Model parsed from response
#property(nonatomic, strong) id parsedModel;
/// Original response string from server
#property(nonatomic, copy) NSString *responseString;
#end

If you can write [response.json firstObject] in Objective C, then response.json is not a dictionary, but an array.
In your Swift code you cast it to a dictionary, which clearly won't work.

Based on the code you posted your custom object doesn't contain JSON, it contains objects that were created from JSON. As #TheEye pointed out in their answer, your objective C code suggests that what you have is an array of dictionaries.
Swift is more strictly typed than Objective-C.
By default dictionaries and arrays are homogeneous: Dictionaries can only contain key/value pairs where the type of the key is always the same and the type of the value is always the same.
Likewise Swift Arrays are normally typed so that they must contain all the same type of object.
You can create Swift Dictionaries or Arrays that contain generic objects ([AnyObject: AnyObject] for a dictionary or [Anyobject] for an array).
Post the definition of your custom object and it's json property. We need to know how it's declared in order to figure out exactly what you need to do to fix your problem.

First make sure what kind of object you have.
if let jsonDict = json as? [String:AnyObject] {
}
if let jsonArray = json as? [AnyObject]{
}

Related

How to pass a Dictionary to Objective-C method in Swift

I need to pass a Dictionary to a Objective-C method in Swift. In Swift the code is like this:
let modelData: Dictionary<String, [Double]> = getModelData()
result = myChilitags.estimate3D(configAt: configFilePath, forModel: modelData);
(The configure file has nothing to do with this problem, just ignore it.)
I used a .h file:
#interface myChilitags : NSObject
+ (nonnull UIImage *)estimate3D:configAt:(NSString *)configFilePath forModel:(nonnull NSDictionary*) modelData;
#end
The question is that I need to do something with the modelData in the Objective-C method estimate3D but I don't know what to do after I passed the Dictionary value modelData to the method.
I tried to just print the modelData value but all that came out was:
1
I also tried to print the value in the Dictionary like:
std::cout << modelData["face001"] << std::endl;
I am pretty sure that there is a key "face001" in the dictionary but the result was still:
1
I know it must have something to do with NSDictionary and Dictionary but I just don't know what to do.
First of all, a Dictionary in Swift is struct, an NSDictionary is class.
Objective-C is not type-safe so it doesn't show an error.
If you try to do the same in Swift, it will tell you
Cannot assign value of type '[String : [Double]]' to type 'NSDictionary'
let swiftDictionary = [String: [Double]]()
var nsDictionary = NSDictionary()
nsDictionary = swiftDictionary //shows error
So you have to convert the Swift dictionary to an NSDictionary.
let modelData: Dictionary<String, [Double]> = getModelData()
let nsModelData = NSDictionary(dictionary: modelData)
result = myChilitags.estimate3D(configAt: configFilePath, forModel: nsModelData);

Reading NSNotification userInfo in Swift

(I'm new to Swift and iOS development in general).
I'm porting some Objective-C code over to Swift and I don't know how to translate this:
-(void) fooDidBar:(NSNotification *)notification
{
Foo* foo = [[notification userInfo] objectForKey:BarKey];
// do stuff with foo
}
So far I have this:
private func fooDidBar(notification: NSNotification) {
var foo: Foo = notification.userInfo.objectForKey(BarKey)
}
But I get a compiler error:
/Users/me/src-me/project/FooBarViewController.swift:53:57: Value of type '[NSObject : AnyObject]?' has no member 'objectForKey'
As userInfo is declared as an NSDictionary in UIApplicationShortcutItem.h:
#property (nullable, nonatomic, copy) NSDictionary<NSString *, id <NSSecureCoding>> *userInfo;
...I thought I'd try this:
= notification.userInfo[BarKey]
but then I get this error:
/Users/me/src-me/project/FooBarViewController.swift:53:65: Type '[NSObject : AnyObject]?' has no subscript members
Your idea to use subscripts was correct, however as you can see by the presence of ?, the userInfo dictionary is Optional, meaning that it can be nil (in Objective-C, no distinction is made). Furthermore, Swift's Dictionary is not as lenient with types as NSDictionary, so you'll need to use as? to ensure the value is a Foo instance as you expect.
You can't directly subscript the optional dictionary, but if you use a ? for optional chaining, then you can access the value if the dictionary is non-nil. I would also recommend if let to access the final value if it's non-nil. (Or you might choose to use guard let with a fatalError or return in case the Foo is not present.)
if let foo = notification.userInfo?[BarKey] as? Foo {
// foo is non-nil (type `Foo`) in here
}

Could not cast value of type '__NSArrayM' to 'NSDictionary'

I have a json.I am trying to parse that with that code.But its says
Could not cast value of type '__NSArrayM' to 'NSDictionary'
do {
let dataDictionary: NSDictionary = try NSJSONSerialization.JSONObjectWithData(responseObject as! NSData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary // <------ Error
if let customerArray = dataDictionary.valueForKey("cart") as? NSArray {
for js in customerArray {
let nameArray = js.valueForKey("name")
let idArray = js.valueForKey("id")
}
}
}
Thank you for your helps
The root object in your data is an array, not a object (dictionary).
You need to dynamically decide how to handle your JSON depending on the deserialized object.
What it's telling you is that the JSON object that you're parsing is not a dictionary, it's an array. So if you change it so that you treat its value as an array instead of a dictionary, you'll be able to iterate over that.
You need to reevaluate your JSON to ensure that it's structured the way you think it is. It would also be useful if you posted the JSON that you're trying to parse so that we can see it's structure as well.

Cannot assign a value of type 'NSArray' to a value of type '[AnyObject]'

In swift, I have an School class, it has an students property of type [AnyObject]!
class School : NSObject {
var students: [AnyObject]!
...
}
I got an instance of School, and an NSArray of string representing students' names. I want to assign this NSArray variable to students:
var school = School()
var studentArray : NSArray = getAllStudents()
//ERROR:Cannot assign a value of type 'NSArray' to a value of type '[AnyObject]'
school.students = studentArray
Why this error? Isn't array in swift compatible with NSArray in objective c??? How to get rid of above compiler error?
Your var students is a Swift array and expects object of type AnyObject, but you try assign it an NSArray. The two objects are not of the same type and it doesn't work.
But, given that NSArray is compatible with [AnyObject], you can use simple typecasting to make the NSArray into a Swift array:
school.students = studentArray as [AnyObject]
Of course a better approach would be to stay in the Swift world and to forget NSArray altogether if possible, by making getAllStudents return a Swift array instead of an NSArray. Not only you will avoid having to do typecasts but you will also benefit from the power of the Swift collections.
Sounds like school.students is defined as Optional and might be nil therefore if you are sure that its not nil - unwrap it first by using !:
school.students as AnyObject! as NSArray
OR
school.students! as NSArray
My method written in object c which return NSMutableArray of type "Database"
-(NSMutableArray *)AllRowFromTableName:(NSString *)tableName;
In swift i declare variable as
var petListArray: NSMutableArray = []
Save in model array as
self.petListArray = self.dataBase.AllRowFromTableName("InsuranceTable")
Used in cellForRowAtIndexPath
let tempDBObject = self.petListArray[indexPath.row] as! Database
cell?.petName.text = tempDBObject.Hname
hope this help someone.

Array supports values of any type

As per swift doc -
“An array stores values of the same type in an ordered list.”
Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/in/jEUH0.l
var justBlankArray = []
var a:Int = 4
var b:Dictionary = ["Address":"Silver Oaks"]
justBlankArray = ["Tush",a,b]
println(justBlankArray[0].classForCoder)
println(justBlankArray[1].classForCoder)
println(justBlankArray[2].classForCoder)
Output-
NSString
NSNumber
NSDictionary
Can anyone tell me what is going on? Are they not of different type in a array?
Created justBlankArray is NSArray-type, which is not Swift-type Array. If you want to store any type of objects in Swift-type Array, you can do that:
var justBlankArray : [AnyObject] = []
It creates an array which can hold any type of object. Even C-structs, what NSArray cannot.
When you create the array like:
var justBlankArray = []
The type will be NSArray, NSArray can hold heterogeneous data. (Means it can hold any object)
If you print the class of the justBlankArray using:
println(justBlankArray.classForCoder)
It'll give you NSArray as result.
If you don't specify a type for array literal it is inferred as NSArray. NSArray can hold any type of class objects (AnyObject).

Resources