Here I got from JSON
[{"photo":null}]
and I use this code
NSMutableArray *jPhoto = [NSMutableArray arrayWithArray:(NSArray *)[jsonDict valueForKey:#"photo"]];
How can I check it if I want to use if() ??
edit
here is JSON Data
[{"photo":
[{"image":"http:\/\/www.yohyeh.com\/upload\/shisetsu\/13157\/photo\/1304928459.jpg","title":"test picture","content":"this is description for test picture.\r\n\u8aac\u660e\u6587\u306a\u306e\u306b\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb\u30fb"}
,{"image":"http:\/\/www.yohyeh.com\/upload\/shisetsu\/13157\/photo\/1304928115.jpg","title":"nothing","content":"iMirai"}
,{"image":"http:\/\/www.yohyeh.com\/upload\/shisetsu\/13157\/photo\/1303276769.jpg","title":"iMirai","content":"Staff"}]}
]
and here is my JSON parser
NSError *theError = nil;
NSString *URL = [NSString stringWithFormat:#"http://www.yohyeh.com/apps/get_sub_detail.php?id=%#&menu=photo",g_id];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]];
NSURLResponse *theResponse =[[[NSURLResponse alloc]init] autorelease];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&theError];
NSMutableString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [string JSONValue];
Thank for help
I believe most JSON parsers represent null as [NSNull null].
Considering jsonDict points to that single element in the array, then the following should work:
if ([jsonDict objectForKey:#"photo"] == [NSNull null]) {
// it's null
}
Edit based on comment: so jsonDict, despite its name, is an array. In that case, rename jsonDict to jsonArray to avoid further confusion. Then, considering jsonArray points to an array similar to the example posted in the question:
NSArray *photos = [jsonArray valueForKey:#"photo"];
for (id photo in photos) {
if (photo == [NSNull null]) {
// photo is null
}
else {
// photo isn't null
}
}
Further edit based on OP’s modified question:
NSArray *jsonArray = [string JSONValue];
NSArray *photos = [jsonArray valueForKey:#"photo"];
for (id photo in photos) {
if (photo == [NSNull null]) {
// photo is null
}
else {
// photo isn't null. It's an array
NSArray *innerPhotos = photo;
…
}
}
Macros can be helpful if payload is complex JSON structure having possible values.
#define SET_IF_NOT_NULL(TARGET, VAL) if(VAL != [NSNull null]) { TARGET = VAL; }
and macro can be referenced like
SET_IF_NOT_NULL(myRecord.name, [jsonData objectForKey:#"name"]);
There's no easy way of dealing with this, but the way I do it is to make a category on NSObject:
#interface NSObject (NotNull)
- (instancetype)notNull;
#end
Implemented like so:
#implementation NSObject (NotNull)
- (instancetype)notNull
{
return self;
}
#end
#implementation NSNull (NotNull)
- (instancetype)notNull
{
return nil;
}
#end
Then you can send notNull to any optional object in a JSON dict and you'll get nil
back if it's NSNull. Otherwise you get the original object. For example:
self.parentIdentifier = [dictionary[#"parent_id"] notNull];
try to check for [jPhoto count] or [NSNull null]
Hope so this helps.
-(NSMutableDictionary *)jsonCheckforNull:(NSMutableDictionary *)json{
NSMutableDictionary* strongjson=[json mutableCopy];
for (NSString *ktr in json) {
NSObject *str=[json objectForKey:ktr];
if ([str isKindOfClass:[NSArray class]]) {
if (!(str==[NSNull null])) {
NSArray *temp = [json allKeysForObject:str];
str=[[self ArrayCheckforNull:(NSMutableArray*)str]mutableCopy];
NSString *key = [temp objectAtIndex:0];
[strongjson removeObjectForKey:key];
[strongjson setObject:str forKey:key];
}
else
{
NSArray *temp = [strongjson allKeysForObject:str];
NSString *key = [temp objectAtIndex:0];
[strongjson removeObjectForKey:key];
[strongjson setObject:#"-----" forKey:key];
}
}
else if ([str isKindOfClass:[NSDictionary class]]) {
if (!(str==[NSNull null])) {
str=[[self jsonCheckforNull:str]mutableCopy];
NSArray *temp = [strongjson allKeysForObject:str];
NSString *key = [temp objectAtIndex:0];
[strongjson removeObjectForKey:key];
[strongjson setObject:str forKey:key];
}
else
{
NSArray *temp = [strongjson allKeysForObject:str];
NSString *key = [temp objectAtIndex:0];
[strongjson removeObjectForKey:key];
[strongjson setObject:#"-----" forKey:key];
}
}
else {
if (str ==[NSNull null]) {
NSArray *temp = [strongjson allKeysForObject:str];
NSString *key = [temp objectAtIndex:0];
[strongjson removeObjectForKey:key];
[strongjson setObject:#"----" forKey:key];
}
}
}
return strongjson;
}
-(NSMutableArray *)ArrayCheckforNull:(NSMutableArray *)arr{
NSObject *str;
NSMutableArray* strongArray=[[[NSMutableArray alloc]initWithArray:arr]mutableCopy];
for (str in arr)
{
if ([str isKindOfClass:[NSArray class]]) {
if (!(str==[NSNull null])) {
str=[[self ArrayCheckforNull:(NSMutableArray *)str]mutableCopy];
[strongArray removeObjectAtIndex:0];
[strongArray addObject:str];
}
else
{
[strongArray removeObject:str];
[strongArray addObject:#"----"];
}
}
else if ([str isKindOfClass:[NSDictionary class]]) {
if (!(str==[NSNull null])) {
str=[[self jsonCheckforNull:(NSMutableDictionary*)str]mutableCopy];
[strongArray removeObjectAtIndex:0];
[strongArray addObject:str];
}
else
{
[strongArray removeObject:str];
[strongArray addObject:#"----"];
}
}
else {
if (str ==[NSNull null]) {
[strongArray removeObject:str];
[strongArray addObject:#"----"];
}
}
}
return strongArray;
}
Related
Below is a class to read and write data using nsarchive
Data.m
-(id)init {
self = [super init];
if(self) {
arr = [[NSMutableArray alloc] init];
}
return self;
}
-(NSString *)getPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath;
if ([paths count] > 0)
documentPath = [paths objectAtIndex:0];
NSString *draftDataPath = [documentPath stringByAppendingPathComponent:#"draftData.dat"];
return draftDataPath;
}
-(void)saveDataToDisk {
NSString *path = [self getPath];
[NSKeyedArchiver archiveRootObject:arr toFile:path];
}
-(void)loadDataFromDisk {
NSString *path = [self getPath];
self.arr = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
}
At later on, I am adding some objects into arr by doing
CustomerClass.m
- (void) viewDidLoad {
Data *data = [[Data alloc] init];
[data.arr addObject:myObject1]
[data.arr addObject:myObject2]
[data.arr addObject:myObject3]
[data saveDataToDisk];
}
At DisplayData.m, I want to check data.arr by
- (void) viewDidLoad {
Data *data = [[Data alloc] init];
[data loadDataFromDisk];
NSLog(#"length of array is %d",[data.arr count]);
}
On the console, I am getting
length of array is 1
I thought it should be 3 after all.
Please point out what I have just made a mistake in the middle of work if you have any clues about it.
So, I suspect that your "myObjects" are not NSCoding compliant. I just did this:
NSMutableArray *arr = [NSMutableArray arrayWithCapacity:3];
[arr addObject:#"Hello"];
[arr addObject:#" "];
[arr addObject:#"World"];
BOOL ret = [NSKeyedArchiver archiveRootObject:arr toFile:[self getPath]];
NSArray *arr2 = [NSKeyedUnarchiver unarchiveObjectWithFile:[self getPath]];
NSLog(#"count = %d", [arr2 count]);
And the results was "count = 3"
I feel like there's too much code here to do what you're looking for. I think all you need is:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:dataClass] forKey:NSUserDefaultString];
[[NSUserDefaults standardUserDefaults] synchronize];
to save it.
And:
NSData *someData = [[NSUserDefaults standardUserDefaults] objectForKey:NSUserDefaultString];
if (settingsData != nil)
{
dataClass = [NSKeyedUnarchiver unarchiveObjectWithData:settingsData];
}
to retrieve it.
I need to extract a variable's value from a string, which happens to be a URL. The string/url is loaded as part of a separate php query, not the url in the browser.
The url's will look like:
http://gmail.com?access_token=ab8w4azq2xv3dr4ab37vvzmh&token_type=bearer&expires_in=3600
How can I capture the value of the access_token which in this example is ab8w4azq2xv3dr4ab37vvzmh?
This code should do it:
- (NSString *)extractToken:(NSURL *)URL
{
NSString *urlString = [URL absoluteString];
NSRange start = [urlString rangeOfString:#"access_token="];
if (start.location != NSNotFound)
{
NSString *token = [urlString substringFromIndex:start.location+start.length];
NSRange end = [token rangeOfString:#"&"];
if (end.location != NSNotFound)
{
//trim off other parameters
token = [token substringToIndex:end.location];
}
return token;
}
//not found
return nil;
}
Alternatively, here is a more general solution that will extract all the query parameters into a dictionary:
- (NSDictionary *)URLQueryParameters:(NSURL *)URL
{
NSString *queryString = [URL query];
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSArray *parameters = [queryString componentsSeparatedByString:#"&"];
for (NSString *parameter in parameters)
{
NSArray *parts = [parameter componentsSeparatedByString:#"="];
NSString *key = [[parts objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if ([parts count] > 1)
{
id value = [[parts objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[result setObject:value forKey:key];
}
}
return result;
}
Good Category for NSDictionary:
#import "NSDictionary+URL.h"
#implementation NSDictionary (URL)
+ (NSDictionary *)dictionaryWithUrlString:(NSString *)urlString{
NSRange urlRange = [urlString rangeOfString:#"?"];
if(urlRange.length>0){
urlString = [urlString substringFromIndex:urlRange.length+urlRange.location];
}
NSArray *pairsArray = [urlString componentsSeparatedByString:#"&"];
NSMutableDictionary *parametersDictionary = [[NSMutableDictionary alloc] initWithCapacity:[pairsArray count]];
for(NSString *pairString in pairsArray){
NSArray *valuesArray = [pairString componentsSeparatedByString:#"="];
if([valuesArray count]==2){
[parametersDictionary setValue:[valuesArray objectAtIndex:1] forKey:[valuesArray objectAtIndex:0]];
}
}
return [parametersDictionary autorelease];
}
#end
NSMutableDictionary *querycomponent = [[NSMutableDictionary alloc] init];
if (![query isEqualToString:#""]){
NSArray *queryArray = [query componentsSeparatedByString:#"&"];
for (NSString *subquery in queryArray){
NSArray *subqueryArray = [subquery componentsSeparatedByString:#"="];
NSString *key = [subqueryArray objectAtIndex:0];
NSString *val = [subqueryArray objectAtIndex:1];
[querycomponent setObject:val forKey:key];
}
NSLog(#"querycomponent %#",querycomponent);
}
it shows me warning that initWithDocPath not found when i want to get private directory content..
+ (NSMutableArray *)loadScaryBugDocs {
NSString *documentsDirectory = [VideoDatabase getPrivateDocsDir];
NSError *error;
NSArray *files =[NSFileManagerdefaultManager]contentsOfDirectoryAtPath:documentsDirectory error:&error];
if (files == nil) {
return nil;
}
NSMutableArray *retval = [NSMutableArray arrayWithCapacity:files.count];
for (NSString *file in files) {
if ([file.pathExtension compare:#"scarybug" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:file];
VideoNotepadViewController *doc = [[[VideoNotepadViewController alloc] initWithDocPath:fullPath] autorelease];
//shows warning here
[retval addObject:doc];
}
}
return retval;
}
You need to implement the initWithDocPath: method in VideoNotepadViewController. Apple doesn't provide a method by that name.
How can I parse a mailto request ?
'mailto:someone#example.com?cc=someone_else#example.com&subject=This%20is%20the%20subject&body=This%20is%20the%20body'
From this NSURL, I want to extract the recipient, the subject and the body. How should I do ?
Thanks
Here is some code that will parse any URL and return a dictionary with the parameters and the associated objects in a dictionary. It works for mailto URLs, too.
Please note: This code assumes you're using ARC!
#interface NSString (URLDecoding)
- (NSString *) URLDecodedString;
#end
#implementation NSString (URLDecoding)
- (NSString *) URLDecodedString {
NSString *result = (__bridge_transfer NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (__bridge CFStringRef)self, CFSTR(""), kCFStringEncodingUTF8);
return result;
}
#end
- (NSDictionary *) parameterDictionaryFromURL:(NSURL *)url {
NSMutableDictionary *parameterDictionary = [[NSMutableDictionary alloc] init];
if ([[url scheme] isEqualToString:#"mailto"]) {
NSString *mailtoParameterString = [[url absoluteString] substringFromIndex:[#"mailto:" length]];
NSUInteger questionMarkLocation = [mailtoParameterString rangeOfString:#"?"].location;
[parameterDictionary setObject:[mailtoParameterString substringToIndex:questionMarkLocation] forKey:#"recipient"];
if (questionMarkLocation != NSNotFound) {
NSString *parameterString = [mailtoParameterString substringFromIndex:questionMarkLocation + 1];
NSArray *keyValuePairs = [parameterString componentsSeparatedByString:#"&"];
for (NSString *queryString in keyValuePairs) {
NSArray *keyValuePair = [queryString componentsSeparatedByString:#"="];
if (keyValuePair.count == 2)
[parameterDictionary setObject:[[keyValuePair objectAtIndex:1] URLDecodedString] forKey:[[keyValuePair objectAtIndex:0] URLDecodedString]];
}
}
}
else {
NSString *parameterString = [url parameterString];
NSArray *keyValuePairs = [parameterString componentsSeparatedByString:#"&"];
for (NSString *queryString in keyValuePairs) {
NSArray *keyValuePair = [queryString componentsSeparatedByString:#"="];
if (keyValuePair.count == 2)
[parameterDictionary setObject:[[keyValuePair objectAtIndex:1] URLDecodedString] forKey:[[keyValuePair objectAtIndex:0] URLDecodedString]];
}
}
return [parameterDictionary copy];
}
And here is how you use it:
NSURL *mailtoURL = [NSURL URLWithString:#"mailto:foo#example.com?cc=bar#example.com&subject=Greetings%20from%20Cupertino!&body=Wish%20you%20were%20here!"];
NSDictionary *parameterDictionary = [self parameterDictionaryFromURL:mailtoURL];
NSString *recipient = [parameterDictionary objectForKey:#"recipient"];
NSString *subject = [parameterDictionary objectForKey:#"subject"];
NSString *body = [parameterDictionary objectForKey:#"body"];
EDIT:
I updated the code to work with any URL and recipients are now in the dictionary for mailto URLs.
I would pull the email from that like this:
NSString * mailToString = #"'mailto:someone#example.com?cc=someone_else#example.com&subject=This%20is%20the%20subject&body=This%20is%20the%20body'";
NSArray *tempArray = [mailToString componentsSeparatedByString:#"?"];
//get email address from array
NSString * emailString = [[tempArray objectAtIndex:0]description];
//clean up string
emailString = [emailString stringByReplacingOccurrencesOfString:#"'mailto:" withString:#""];
//and here is your email string
NSLog(#"%#",emailString);
Since iOS 7 this is easily doable with NSURLComponents. You can create that object with:
if let components = NSURLComponents(URL: url, resolvingAgainstBaseURL:false) { ...
Then you can get the recipient accessing the path property of NSURLComponents; and the parameters with the queryItems property. For instance, if we wanted to get the subject, something like this would do our job
let queryItems = components.queryItems as? [NSURLQueryItem]
let subject = queryItems?.filter({$0.name == "subject"}).first?.value
NSURL category for just mailto: This method also has a fix for a crash bug in Fabian's answer above when mailto: url doesn't contain a ?. It also doesn't require the URLDecodedString category method.
#implementation NSURL (Additions)
- (NSDictionary *) parameterDictionaryForMailTo {
NSMutableDictionary *parameterDictionary = [[NSMutableDictionary alloc] init];
NSString *mailtoParameterString = [[self absoluteString] substringFromIndex:[#"mailto:" length]];
NSUInteger questionMarkLocation = [mailtoParameterString rangeOfString:#"?"].location;
if (questionMarkLocation != NSNotFound) {
[parameterDictionary setObject:[mailtoParameterString substringToIndex:questionMarkLocation] forKey:#"recipient"];
NSString *parameterString = [mailtoParameterString substringFromIndex:questionMarkLocation + 1];
NSArray *keyValuePairs = [parameterString componentsSeparatedByString:#"&"];
for (NSString *queryString in keyValuePairs) {
NSArray *keyValuePair = [queryString componentsSeparatedByString:#"="];
if (keyValuePair.count == 2)
[parameterDictionary setObject:[[keyValuePair objectAtIndex:1] stringByRemovingPercentEncoding] forKey:[[keyValuePair objectAtIndex:0] stringByRemovingPercentEncoding]];
}
}
else {
[parameterDictionary setObject:mailtoParameterString forKey:#"recipient"];
}
return [parameterDictionary copy];
}
- (NSDictionary *) parameterDictionaryFromURL:(NSURL *)url {
NSMutableDictionary *parameterDictionary = [[NSMutableDictionary alloc] init];
NSURLComponents * urlComponents = [NSURLComponents componentsWithString:url.absoluteString];
for (NSURLQueryItem *item in urlComponents.queryItems) {
parameterDictionary[item.name] = item.value;
}
if ([url.scheme isEqualToString:#"mailto"]) {
NSUInteger questionMarkLocation = [url.resourceSpecifier rangeOfString:#"?"].location;
if (questionMarkLocation == NSNotFound) {
parameterDictionary[#"recipient"] = url.resourceSpecifier;
} else {
parameterDictionary[#"recipient"] = [url.resourceSpecifier substringToIndex:questionMarkLocation];
}
}
return [parameterDictionary copy];
}
here is xml
Root--->
Subject--->
SubjectID 1 /SubjectID
SubjectName MatheMatics /SubjectName
Sub_Subject---->
Sub_SubjectID 1 /Sub_SubjectID
Sub_SubjectName Calculus /Sub_SubjectName
/Sub_Subject
Sub_Subject
Sub_SubjectID 2 /Sub_SubjectID
Sub_SubjectName Geometry /Sub_SubjectName
/Sub_Subject
/Subject
Subject---->
SubjectID 2 /SubjectID
SubjectName Physics /SubjectName
/Subject
/Root
in app i want to show subject name in tableviewcontroller when application launch & when we clicked on tableviewcell it leads on another table view which shows sub_subject list.
how to achieve this
for that.
+ (NSString *)dataFilePath:(BOOL)forSave {
return [[NSBundle mainBundle] pathForResource:#"SubjectData" ofType:#"xml"];
}
+ (RootSubject *)loadParty {
NSString *filePath = [self dataFilePath:FALSE];
NSData *xmlData = [[NSMutableData alloc] initWithContentsOfFile:filePath];
NSError *error;
GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:xmlData
options:0 error:&error];
/* if (doc == nil) { return nil; }
NSLog(#"%#", doc.rootElement);
[doc release];
[xmlData release];
return nil;*/
RootSubject *rootSubject = [[[RootSubject alloc] init] autorelease];
NSArray *partyMembers = [doc nodesForXPath:#"//Root/Subject" error:nil];
//NSArray *patry = [doc nodesForXPath:#"//Root/Subject/SunjectID" error:nil];
for (GDataXMLElement *partyMember in partyMembers) {
// Let's fill these in!
NSString *subjectId, *subjectName, *sub_SubjectId, *sub_SubjectName;
// senderName
NSArray *subjectIds = [partyMember elementsForName:#"SubjectID"];
if (subjectIds.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [subjectIds objectAtIndex:0];
subjectId = firstName.stringValue;
} else continue;
// senderEmail
NSArray *subjectNames = [partyMember elementsForName:#"SubjectName"];
if (subjectNames.count > 0) {
GDataXMLElement *firstLevel = (GDataXMLElement *) [subjectNames objectAtIndex:0];
subjectName = firstLevel.stringValue;
} else continue;
/* //senderPhone
NSArray *sub_SubjectIds = [partyMember elementsForName:#"Sub_SubjectID"];
if (sub_SubjectIds.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [sub_SubjectIds objectAtIndex:0];
sub_SubjectId = firstName.stringValue;
} else continue;
//senderLocation
NSArray *sub_SubjectNames = [partyMember elementsForName:#"Sub_SubjectName"];
if (sub_SubjectNames.count > 0) {
GDataXMLElement *firstName = (GDataXMLElement *) [sub_SubjectNames objectAtIndex:0];
sub_SubjectName = firstName.stringValue;
} else continue;*/
//Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:subjectName sub_SubjectId:sub_SubjectId sub_SubjectName:sub_SubjectName]autorelease];
Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:subjectName sub_SubjectId:nil sub_SubjectName:nil]autorelease];
//Subject *subject = [[[Subject alloc]initWithSubjectId:subjectId subjectName:nil sub_SubjectId:sub_SubjectId sub_SubjectName:sub_SubjectName]autorelease];
//[rootGroup.groups addObject:group];
[rootSubject.subjects addObject:subject];
}
[doc release];
[xmlData release];
return rootSubject;
}
through this we get subject name and show it perfectly in tableviewcontroller but when i clicked on particular subject which provides subsubject in another view controller
Here is a good tutorial that shows XML parsing using GDataXMLParser.
how-to-read-and-write-xml-documents-with-gdataxml