Replacement for use of nil in dictionaries in objective-C - iphone

I'm working in the IPhone SDK, and am pretty new to objective-c. Right now I'm working with NSUserDefaults to save and restore setting on my IPhone app. In order to save the classes that have been created, I encode them into dictionary form, and then save the NSdictionary.
My problem is that I can't find a reasonable way to store a non-value (I.E. a class variable that is nil) in the dictionary in a reasonable way. To be more specific, lets say I have a class "Dog" and it's got NSString *tail-color. Lets say I'm trying to save a class instance of a dog without a tail, so tail-color for that instance is nil. What is a reasonable way of saving dog as a dictionary? It won't let me save nil into the NSdictionary. #"" isn't good, because if I do if(#""), #"" is true. I would like it to be false like nil.
I hope my question makes sense, and thanks for your help!

If you don't store anything for that key, nil will be returned when you call objectForKey:. If you check for nil when reading the data in, would that be enough? Optionally, you can use objectsForKeys:notFoundMarker: that will return a default value instead of nil.
So, store nothing at all in the dictionary for a value you don't have, and use a strategy for handling that value missing when reading.
You could use NSNull, but that doesn't feel standard, IMO.

You can use NSNull. Instantiate it like this:
[NSNull null]
I would recommend Archiving to save and restore your objects, however.

You should use NSNull to represent nil objects in collections

The best solution is to not save the values which are 'nil' in your case. While reading if the value is not present for your given key the dictionary will return you 'nil'.

Related

Swift - Empty NSMutableDictionary or NSDictionary? Optional

Just curious, in Swift, is it more ideal to initialize an empty NSMutableDictionary variable, NSMutableDictionary = [:], and later re-assign its value to a new dictionary (coming from an API for example),
OR, is it better to declare an optional NSDictionary, NSDictionary? and assign it to a new dictionary?
So with Swift it would technically be best practice to use a Dictionary type. Like this for example:
var dict: Dictionary<String, Int>
If you need the dictionary as a whole to be able to be nil use an optional.
This depends on your needs, do you want it to be nil sometimes? is it nil sometimes?
If an array is always gonna have value, even if it's an empty value, I personally like to Initialize it right away, and not hassle with unwrapping everywhere.
Maybe if you had two arrays, one was normal array, and the second one was a searched result. You might wanna check if searched result is nil first, if it is, show the array1, if it isn't show it instead.
And this is implying you only search "sometimes", thus that array is only sometimes used - so you might as well have that deallocated when not in use, if you aren't using it most of the time.
EDIT: I've been using arrays in my example, but same applies for a dictionary in those situations.
EDIT: In Swift It's best to avoid 'NS' classes, sometimes you have to use them, sure. But Swift's Dictionary does the job.
Example:
var sometimesUselessDict: Dictionary<String, AnyObject>?
var alwaysUsedDictionary = Dictionary<String, AnyObject>()
Cheers
You should make it optional only if you need to be able to distinguish a dictionary that's empty from one that doesn't exist at all. For instance, if you're receiving data from a server, you might want to distinguish between a successful response that returned no data (empty dictionary) and a failed or invalid response (nil).
If that distinction isn't important, I would always go with a non-optional to avoid unnecessary unwrapping.

CoreData Object typing won't work

Can someone explain to me why this doesn't work:
CoreDataClass *classObject = (CoreDataClass *)[some method that returns a dictionary with exact KVC pairs that match CoreDataClass];
NSString *myString = classObject.stringProperty;
But this does:
CoreDataClass *classObject = (CoreDataClass *)[some method that returns a dictionary with exact KVC pairs that match CoreDataClass];
NSString *myString = [classObject valueForKey:#"stringProperty"];
EDIT:
What's the easiest way to cast the dictionary as my NSManagedObjectClass CoreDataClass so I can access properties directly?
It doesn't work since KVC compliance is not at all what defines classes or makes them castable - the class hierarchy exists for a reason, and just ensuring adherence to certain methods doesn't magically make something an instance of a completely different class. Keep in mind that the dot-accessor syntax is just sugar for a method send, so these two are equivalent:
classObject.stringProperty
[classObject stringProperty]
...and the latter obviously isn't valid for instances of NSDictionary (i.e. [[NSDictionary class] instancesRespondToSelector:#selector(stringProperty)] is NO).
Your latter example works because of the very premise of your question: if something is KVC-compliant for the key stringProperty, and you ask it for a value for that key, then obviously you get something back. Furthermore, both NSDictionary and CoreDataClass respond to the selector -valueForKey:, so the message send actually works at runtime.
The best way to get the two across isn't a "cast" at all - it's a complete conversion, at the property level, of the data involved. You might consider creating a custom -initWith... method on CoreDataClass that lets you instantiate its properties from a dictionary, or finding a way to get your method to return an actual instance of CoreDataClass instead of an NSDictionary.
Note that this solution may differ from the "easiest" way to get the data across, which is effectively to keep doing what you're doing and use -valueForKey: (though preferably without the cast, which is misleading).
Casting objects only appears to work (in the sense that you won't get type-checking errors) because it's a hint to the compiler, but it doesn't actually change anything about what the pointer points to, so you are still pointing to an NSDictionary. This is because, at the end of the day, you are essentially casting a pointer to a pointer, but telling Xcode that you are allowed to send a different set of selectors to it.
For NSManagedObjects, creation from a dictionary depends on a few things, but the recommended way is to make a class method on your custom class which will use NSEntityDescription and you NSManagedObjectContext, and sets the properties from the dictionary to the object:
+(CoreDataClass *) coreDataObjectWithDictionary:(NSDictionary *) spec {
CoreDataClass *myInstance = [NSEntityDescription insertNewObjectForEntityForName: #"CoreDataClass" inManagedObjectContext: [myMOCProvider sharedMOC];
myInstance.someProp = [spec valueForKey:#"someProp"];
}

NSUserDefaults setObject and IntegerForKey, use on the same key, if not how can I workaround?

I need to iterate through all the keys in my NSUserDefaults and transfer them to another format. Later I'll want to transfer them back, programatically.
I have a lot of keys and I have no way in my naming convention or by other means to determine if I used setObject or setInteger etc.
If I use setObject will this enable me to use integerForKey on that key ?
If I can't want can I use instead?
No, you should not be able to get the correct objects if you use integerForKey:. However you could get the correct objects if you use objectForKey:. This is because if you had used setInteger:forKey:, it automatically calls setObject:forKey:. So, there will be an object for the key. So what you have to do is iterate through the keys, get the objects using objectForKey: and convert it to the data type that you want.
I'm pretty sure using setObject will allow you to use integerForKey later.
Another way to go could be by adding a plist to your project and store everything in there. It's basically the same as NSUserDefaults is doing, only you'll be doing it all by hand. You can just read the contents of a plist to either an NSArray or an NSDictionary (whichever you chose to construct it with in the first place) and then access the members you need from that object.
Hope this helps.

Check for iVar's Names with respect to NSDictionary keys

I am parsing the values of Json object to my data model, and I am trying to figure out if there is any way to compare the name of the iVar's set for are the same with respect to dictionary keys. I am sure there is a good way to do that, but just can't find the method somehow.
Thanks.
It's a little hard to tell what you're asking, but I think you want Key-Value Coding. In particular, setValuesForKeysWithDictionary: will let you pass a dictionary of property or ivar names and set them for you.

How to store object + string pairs without retaining the objects, and what kind of storage to use?

I am implementing a class that has to store arbitrary objects together with a string. i.e.
myUIViewObject, #"that's a nice view"
myUIViewController, #"not really special"
myOtherObject, #"very important one"
this list can be extended and modified at any time, so I thought about using NSMutableDictionary here. But I am not really sure...
The object should be the key, i.e. I want to find easily the matching string for myUIViewController or myOtherObject when I ask for it like so:
- (NSString*)checkObjNoteStringForObject:(id)anyObjectInList;
The other problem is, that when an object gets added to that "list", I don't want it to be retained because of that. NSMutableDictionary retains it's contents, right? Could I just send a -release afterwards to undo this unwanted behaviour, and when removing from the list just sending -retain before doing so? Or is there a more elegant way?
What do you suggest? Thanks # all!
If your dictionary key is not retained, once it is deallocated accesses to the dictionary will lead to undefined behaviour (in practice, they'll crash if a lookup happens to hit that dictionary element). To do what you want, you need a strategy to remove the objects from the dictionary when necessary.
If you do have one – for instance, overriding the objects’ -dealloc and removing them from there – you can do what you want using +[NSValue valueWithNonretainedObject:]. The NSValue will refer to your object without retaining it, and the dictionary will copy the NSValue (keys are copied, not retained). Just remember to create an NSValue for each time you want to look something up in the dictionary; a helper function or method is a good idea.