Retrieving values from a multidimensional JSON array - objective-c

Hi i am trying to get the subject name value out of the following JSON file (dataArray), which I have already run through NSJSONSERIALISATION:
-0: {
id: "55edc05848177ec741daf79e"
firstName: "Brad"
rating: 4.2
lessons: 5
text: "Lessons, they're yours take it"
-subjects: [4]
-0: {
name: "Indonesian"
pricePerHour: "500000"
}
-1: {
name: "Diving"
pricePerHour: "700000"
}
But am not able to access if using the indexPath and dot notation I have used for other elements. I'm understanding it must because I have to access an NSDictionary element within two arrays, however haven't been able to find the correct code to do this (though have looked a lot on here, most examples are for much simpler cases).
Here is the code I have been trying, but as I mentioned I now see that this code doesn't cover the array within array of the JSON. How should I modify this to get the value:
// Load and display subjects
UILabel *subjectLabel = (UILabel *)[cell viewWithTag:103];
NSString * subject1String = [dataArray[indexPath.row] valueForKeyPath: #"subjects.0.name"];
subjectLabel.text = [NSString stringWithFormat:#"%#", subject1String];

I think this is not valid Json. Print response as you are getting from the server end. And for getting name : you need to add loop.

Related

how to get dictionary same order as same i am getting from json in objective c

i am parsing json and what i get set of dictionary but after parsing it will automatically change it order. i just need same order as same i am getting from json parsing.
NOTE: i want to make one functionality which depends on dictionary order, i don't want to make it manually. so it will not need to make it every-time to do.it will help to change dynamically in future
Example:
From Json:
Section:
{
category:{},
location:{},
vehicle_type:{},
mode_type:{}
}
after convert into NSDicationary:
Section:
{
vehicle_type:{}
category:{},
location:{},
mode_type:{}
}
Thanks
Order of key:value doesn't matter for JSON, as you can directly access value with the help of key string. An dictionary does not support indexing of elements, so you can't.
Dictionaries are not ordered collections. On other hand, arrays are.
Note, if you don't have access over the json format, you got no guarantees about the order of elements, if you don't have hardcoded logic in your app.
Having said that, let's take a deeper look into your case. It happens that you have one main object in your json that is Section. What is more, you have 4 ordered properties of this object that are of specific kind of their own: 0: category; 1: location; 2: vehicle_type; 3: mode_type. So here comes the good part: just change your json to look something like this:
Section:
[
{
title: "category",
value: {}
},
{
title: "location",
value: {}
},
{
title: "vehicle_type",
value: {}
},
{
title: "mode_type",
value: {}
}
]
Having this json, you just go through the Section ordered elements, check the title of the element, and create the corresponding Object. This way you can achieve what you are after.

Objective-C string wrapped in parentheses?

I'm getting this on console.log;
2014-08-13 11:55:11.877 Wevo[14264:1830541] artist name: (
"Vance Joy"
)
How do I unwrap it so its just the string?
The problem comes because I'm parsing json that looks like this:
output = {
contributor = {
"/music/recording/artist" = [
{
mid = "/m/026hdj4";
name = "Marie-Mai";
}
];
};
};
notice how the mid is wrapped in an array?
So it gets converted to an object literal somewhere
I'm setting the value using:
_artistName = [[attributes[#"output"][#"contributor"][#"/music/recording/artist"] valueForKeyPath:#"name"] copy];
Why are you using valueForKeyPath:? If you use
_artistName = attributes[#"output"][#"contributor"][#"/music/recording/artist"][0][#"name"];
it should come out correctly.
Edit: For future viewers, one off lines like this will work. However, for a more maintainable and debuggable app, I would recommend splitting up the lines to extract only one object per line. That way, if something breaks, the debugger will be a larger help.
For apps where you deal with more JSON than just a one off, I would recommend creating model objects and pulling your JSON into those. There are libraries on github that could also help you there with model objects.

Core Data and unique UIImage per object

I am making a simple app where the user can create severals objects which are saved with CoreData.
My problem is, I want each object to have an image linked to it. The image is brought by the iphone camera or the user personal Camera roll, so the images will have a pretty high weight (> 1MB each I think).
I read that when the weight of images is that high, the good way to handle this is to save the images in the documentsDirectory folder, and save the path to coreData. I achieved this pretty easily.
But how do I find a path name for the image to be linked to an unique object? CoreData does not really handle unique IDs, and two objects can have the same name... I searched around objectID but it's not working really good and I'm not sure it's the good way to handle this.
Do you have any idea? Is there an other simple way I am totally missing? Thank you in advance.
use coredata's objectID as identifier
id uri = [self sanitizeFilename:coreDataObject.objectID.URIRepresentation];
[NSString stringWithFormat:#"%#.png", uri];
helper sanitizeFilename:
- (NSString *)sanitizeFileNameString:(NSString *)fileName {
NSCharacterSet* illegalFileNameCharacters = [NSCharacterSet characterSetWithCharactersInString:#"/\\?%*|\"<>"];
return [[fileName componentsSeparatedByCharactersInSet:illegalFileNameCharacters] componentsJoinedByString:#""];
}
Just create an object_id number property in your CoreData model entity description and each time a new object is created increment this property by one and assign it to the object, then use a naming convention like
[NSString stringWithFormat:#"object_%d_img.png", idNumber];
And save it to NSDoctumentsDirectory.
Then in object's - (void)prepareForDeletion method delete the image.
As for how to increment the id value, create a method that will fetch an object with biggest id value - simply get all objects with sort descriptor by id desc and use it + 1 when creating a new entity.
Thanks to #Daij-Djan. I created version for Swift:
var itemObjectId:String = item.objectID.URIRepresentation().absoluteString!
var fileName = NSString(format:"%#.png", FileHelper.sanitizeFileNameString(itemObjectId)) as String
Helper for sanitize:
struct FileHelper {
static func sanitizeFileNameString(fileName:String) ->String {
let illegalFileNameCharacters:NSCharacterSet = NSCharacterSet(charactersInString: "/\\?%*|\"<>")
let components : [String] = fileName.componentsSeparatedByCharactersInSet(illegalFileNameCharacters)
let joinedString = join("", components)
return joinedString
}
}
I think you'll need to generate the unique id by your self. Since a user can have several objects. so maybe the image id could be named as such
userId-objectId-somesalt
save the value to the object's path

iOS – Facebook SDK, parsing results

In my -request:didLoad: delegate method I'm NSLoging the results but I can't figure out what's the content?
It looks like result is an NSArray but what is inside it? how do I parse the data?
A sample of the log looks like this:
result: (
{
"fql_result_set" = (
{
uid2 = 1234567;
},
{
uid2 = 12345678;
}
);
name = queryID;
},
{
"fql_result_set" = (
{
"birthday_date" = "05/12/1987";
name = "John Doe";
},
{
"birthday_date" = "03/01/1978";
name = "Jane Doe";
}
);
name = queryBirthday;
}
)
The Facebook iOS tutorial, in "Step 6: Using the Graph API", says
Note that the server response will be in JSON string format. The SDK uses an open source JSON library https://github.com/stig/json-framework/ to parse the result. If a parsing error occurs, the SDK will callback request:didFailWithError: in your delegate.
A successful request will callback request:didLoad: in your delegate. The result passed to your delegate can be an NSArray, if there are multiple results, or an NSDictionary if there is only a single result.
In your example, everything printed by NSLog inside "()" is part of an NSArray, while everything inside "{}" (which also have keys incidentally) is part of an NSDictionary and therefore accessible by key (name).
http://developers.facebook.com/docs/mobile/ios/build/
According to https://developers.facebook.com/docs/reference/api/, all 'responses' are JSON-Objects. To parse these, iOS 5 provides a class called NSJSONSerialization (NSJSONSerialization Class Reference)
You normally parse it as follows:
NSDictionary *dictionaryJSON = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];

NSPredicateEditorRowTemplate, specifying of Key Path with spaces?

As per a previous question, I have reluctantly given up on using IB/Xcode4 to edit an NSPredicateEditor and done it purely in code.
In the GUI way of editing the fields, key paths can be specified with spaces, like 'field name', and it makes them work as 'fieldName'-style key paths, while still displaying them in the UI with spaces. How do I do this in code? When I specify them with spaces, they don't work. When I specify them in camelCase, they work but display in camelCase. I'm just adding a bunch of NSExpressions like this:
[NSExpression expressionForKeyPath:#"original filename"]
The proper way to get human readable strings in the predicate editor's row views is to use the localization capabilities of NSRuleEditor and NSPredicateEditor.
If you follow the instructions in this blog post, you'll have everything you need to localize the editor.
As an example, let's say your key path is fileName, you support 2 operators (is and contains), and you want the user to enter a string. You'll end up with a strings file that looks like this:
"%[fileName]# %[is]# %#" = "%1$[fileName]# %2$[is]# %3$#";
"%[fileName]# %[contains]# %#" = "%1$[fileName]# %2$[contains]# %3$#";
You can use this file to put in human-readable stuff, and even reorder things:
"%[fileName]# %[is]# %#" = "%1$[original filename]# %2$[is]# %3$#";
"%[fileName]# %[contains]# %#" = "%3$# %2$[is contained in]# %1$[original filename]#";
Once you've localized the strings file, you hand that file back to the predicate editor, and it'll pull out the translated values, do its magic, and everything will show up correctly.
If you don't want to localize everything, just map the key paths consider overriding value(forKey:) in your evaluated object like this:
class Match: NSObject {
var date: Date?
var fileName: String?
override func value(forKey key: String) -> Any? {
// Alternatively use static dictionary for mapping key paths
super.value(forKey: camelCasedKeyPath(forKey: key))
}
private func camelCasedKeyPath(forKey key: String) -> String {
key.components(separatedBy: .whitespaces)
.enumerated()
.map { $0.offset > 0 ? $0.element.capitalized : $0.element.lowercased() }
.joined()
}
}