objectForKey string with "/" crashes my app - iphone

Following code works fine:
NSDictionary *item;
if([arrTesting count] >0 )
item = [arrTesting objectAtIndex:0];
// The text "article" is what I'm searching for to ensure it exists
if([item objectForKey:#"article"] != [NSNull null])
{
NSString *mid = [[item objectForKey:#"article"] objectForKey:#"id"];
(more code below...)
But if I replace "article" with "/code/location/article" the app crashes. What gives?? What am I missing??

If a NSDictionary does not contain a specific element, objectForKey: will return nil and not [NSNull null].
So, if the dictionary does not contain the object that you are looking for, you are essentially doing a comparison like nil != [NSNull null] which will always evaluate to true. This is probably not what you want.
(Checking for NSNull means that the entry is there, but has a null value. This is common for for example JSON responses. I am not sure if it is common in your scenario though.)

Related

Find Existence of Key in NSDictionary

How can we identify the object is available for a particular key. I have tried following:
for(NSDictionary *item in jsonArray){
if([item objectForKey:#"EventDate"])
NSLog([item objectForKey:#"EventDate"]);
}
This is getting crash the code with error:
-[__NSCFString objectForKey:]: unrecognized selector sent to instance 0x6a567b0
I have also find many posts that is showing objectForKey will return nil if a key doesn't exists. Than my question is there is also a method in NSDictionary class that is "setNilValueForKey". How is this possible that we cannot specify the NSDictionary key with nil object and also we have the method to set nil value for object in NSDictionary.
Please Suggest on first and also make me clear on second query.
1) Your jsonArray contains other types of objects than NSDictionaries, including at least one NSString. NSString doesn't respond to objectForKey: so it throws an exception when you try to call it. You'll have to look at the JSON to determine how to proceed with whatever you were doing.
2) There is an NSObject method setNilValueForKey: which is related to key-value coding. This isn't really related to NSDictionary. If you really need to represent nil in your dictionary, set [NSNull null] as the object for your key that represents nil.
Hope this helps!
Not all the objects in your array are dictionaries. You need to check what kind of data you're processing before you work on it. Something like this:
for(NSObject* item in jsonArray) {
if ([item isKindOfClass:[NSDictionary class]]) {
// do dictionary stuff
}
else if ([item isKindOfClass:[NSString class]]) {
// do string stuff
}
}
item is not a NSDictionary its a String. So check your jsonArray it may be contains only strings not dictinaries
Answer to second query
There is a non-nil object called NSNull that is built specifically to represent nils in situations where "plain" nil is not acceptable. If you replace your nils with [NSNull null] object, NSDictionary will take them. You would need to check for NSNull on the way out, though.
Refer more here
Answer to first query
for(id *item in jsonArray)
{
if([item isKindofClass:[NSDictionary class])
{
NSArray *allKeys = [item allKeys];
for(NSString *strKey in allKeys)
{
if([strKey isEqualToString:#"EventDate"])
{
// EventDate key has object
NSLog([item objectForKey:#"EventDate"]);
}
}
}
}

How to create a NSArray of unknown NSStrings?

For example, I have #"John", #"Peter", ..., #"May" and need to construct NSArray:
[#"John", #"Peter", ..., #"May"]
The number of NSString is unknown and is taking from an import text file. As NSArray does not support appending new element, how can I create NSArray?
Thanks
UPDATE, let me rephrase the question. How can I create the dynamic array paremeter required by the follow function call?
[segmentedAttributes attributesWithTitlesArray:[NSArray arrayWithObjects:#"John", #"Peter", #"May", nil]]
You don't.
You misunderstand the library behavior.
It is true that there is a convenience constructor arrayWithObjects: which is used thus:
NSArray* array=[NSArray arrayWithObjects:#"Low", #"Medium", #"High", nil];
But this does not create an array with nil at the end. This nil is just to signify the end of the variable-length argument list. It just creates an NSArray with three elements, not four with the last one nil.
You just need to create an NSArray containing the required elements, and pass it to the library function. For example:
NSMutableArray*array=[NSMutableArray array];
while(...){
... get a string ...
[array addObject: string];
}
SCSegmentedAttributes*attributes=[SCSegmentedAttributes attributesWithSegmentTitlesArray:array];
should work, without adding a nil or [NSNull null].
You can't store nil in a Foundation collection class. Instead, you can use [NSNull null]. Use an NSMutableArray, then when you want to add your 'nil' object, use [NSNull null].
Note that when you want to see if an object is [NSNull null] later on, that method will return the same instance every time, so you can do a direct point equality test, like this:
for (id anObject in myArray) {
if (anObject == [NSNull null]) {
NSLog(#"object is nil");
}
else {
NSLog(#"object is not nil: %#", anObject);
}
}
create mutable array then just use
NSString *myString = [NSString stringWithFormat:#"ur new string"];
[myArray addObject:myString];
you have to add object type to array when adding new abject in mutable array.
hope this will help

iPhone - Registering an Array containing NSNulls with NSUserDefaults

I have the Array defined below.
NSMutableArray *tempMPArray = [NSMutableArray arrayWithCapacity:16];
for (int i=0; i < chapters; i++)
{
[tempMPArray addObject:[NSNull null]];
}
Every time I use it as a one of the objects of a dictionary below to register default values it crashes with EXC_BAD_ACCESS.
[[NSUserDefaults standardUserDefaults] registerDefaults:myDict];
If I replace the objects in the array with any other object NSNumber etc it works fine. What am I doing wrong with my array that NSUserDefaults rejects it ? The stack trace or NSZombie does not give any additional info.
While the solution may be a "work-around" I don't think it answers the underlying question. By providing a dictionary with [NSNull null] values he is providing NSUserDefaults with a valid dictionary. Why is it crashing? Is it something he is doing "wrong" or is it a bug in registerDefaults?
There may be circumstances where it is important to know whether say a user has entered a value (ie there is a valid string) or not entered a value (null) and the method of creating a "valid but empty string" can't determine if the empty string was because the user created a string with no characters or if he had never created a string at all. You may want different logic in these two cases.
I'm in the same boat, I have an NSUserDefault value I want to be [NSNull null] and everything I've read suggests the "right" way to put a null value in a dictionary is with [NSNull null] and my dictionary creates fine. But registerDefaults with this valid dictionary causes a crash. That suggests a bug in the implementation of registerDefaults doesn't it? What is wrong with the following and why does it crash?
NSArray *defaultValues = [NSArray arrayWithObjects:[NSNull null], nil];
NSArray *CurrentKeys = [NSArray arrayWithObjects: #"NullKey", nil];
NSDictionary *resourceDict = [NSDictionary dictionaryWithObjects:defaultValues forKeys:CurrentKeys];
[[NSUserDefaults standardUserDefaults] registerDefaults:resourceDict];
Ultimately, i think the answer is that the userDefaults get written out as a plist and plists don't support NSNull. if that's the case, the documentation for registerDefaults should say that only plist object types are allowed in the dictionary
Here's a better solution!
Define a static after #implementation
NSString *const Null = #"";
Then
NSMutableArray *tempDSArray = [NSMutableArray arrayWithCapacity:16];
for (i=0; i < chapters; i++)
{
[tempDSArray addObject:Null];
}
Everything else should work fine!

how to add nil to nsmutablearray?

NSArray *array = [[NSArray alloc] initWithObjects:#"ΕΛΤΑ",
#"ΕΛΤΑ COURIER", #"ACS", #"ACS ΕΞΩΤΕΡΙΚΟ",
#"DHL", #"INTERATTICA", #"SPEEDEX",
#"UPS", #"ΓΕΝΙΚΗ ΤΑΧΥΔΡΟΜΙΚΗ", #"ΜΕΤΑΦΟΡΙΚΕΣ ΕΞΩΤΕΡΙΚΟΥ", nil];
This is working because it has nil at the end.
But I add objects like this: addObject:name etc...
So at the end I have to add nil I do this addObhect:nil but when I run the app it still crashes at cellForRowAtIndexPath:
how can I do this work?
Ok, I dont have to add nil
What is the reason that my app crashes then?
If you must add a nil object to a collection, use the NSNull class:
The NSNull class defines a singleton object used to represent null values in collection objects (which don’t allow nil values).
Assuming "array" is of type NSMutableArray:
....
[array addObject:[NSNumber numberWithInt:2];
[array addObject:#"string"];
[array addObject:[NSNull null]];
You don't need to call [addObject:nil]
The nil in initWithObjects: is only there to tell the method where the list ends, because of how C varargs work. When you add objects one-by-one with addObject: you don't need to add a nil.
You can't add nil when you're calling addObject.
If you really want a Null-ish item in your collection, NSNull is there for that.
You need to add NSNull class and the best way to do it is like this:
NSArray *array = #[ #"string", #42, [NSNull null] ];
I personally recommend to use a specific value like 0 instead of null or nil in your design of your code, but sometimes you need to add null.
There is a good explanation from this Apple reference.
nil is used to terminate the array
nil is not an object that you can add to an array: An array cannot contain nil. This is why addObject:nil crashes.
pass your object through this method when adding to array to avoid attempt to insert nil object from objects crashes.
-(id) returnNullIfNil:(id) obj {
return (obj == nil) ? ([NSNull null]) : (obj);
}
[NSNull null] returns an null object which represents nil.
You can't add an object to an NSArray because that class is immutable. You have to use NSMutableArray if you want to change the array after it is created.

Initial value of a Core Data Entities properties?

I have several core data entities that contains a bunch of empty NSString properties.
I parse some XML and set the properties I can get a hold of and would like to set the "empty" ones to "n/a" as in "not available". So if my XML does not contain the values it sort of tidy up the Entity by giving it a "n/a" string I can test for later on, also should one of these make it to a UILabel it will not display (null) .. which leads me to my question:
I do this to test if the property on the Entity is already sat, is nil or is empty:
for(NSString *s in allPossibleStrings) {
if([[f valueForKey:s] isKindOfClass:[NSString class]] && [[f valueForKey:s] isEqualToString:#""]) {
[f setValue:#"n/a" forKey:s];
}
if ([[f valueForKey:s] isKindOfClass:[NSString class]] && [f valueForKey:s] == nil) {
[f setValue:#"n/a" forKey:s];
}
}
It turns out however that I still end up with a lot of values being displayed as (null).
So I was thinking can the property be something else than #"" empty or (nil)
I believe the NSManagedObject should be KVC compliant so I did a test where I copied my NSManagedObject property by property, only difference is that is is a subclass of just NSObject instead of NSManagedObject.
Sadly this behaves in the exact same way. It also leaves values as (null)
Hope someone can pick up on where I go wrong with these string tests :)
Thank You
You could set the default property value of your entity to "N/A" (that's a good practice, because you might want to use sqlite for iPhone app shipping, and it doesn't work well with null values because sqlite and cocoa don't have the same vision of "null") and set "optional" to "No".
if([[f valueForKey:s] isKindOfClass:[NSString class]] && [[f valueForKey:s] isEqualToString:#"NA"]) {
//Tell your program to know that it's null if it needs to know
}
Cheers
What is allPossibleStrings? You could do this to get to all the properties:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MyEntityName" inManagedObjectContext:moc];
for (NSString *attr in [entity attributesByName]) {
[object setValue:#"n/a" forKey:attr];
}
The issue is that when something is nil, what you can get back from any managed object property (not just strings) is an NSNull object. So if you check also for isKindOfClass:[NSNull class] I think your code will do what you want.