Is there shorthand syntax for creating conditional NSDictionary? - ios

Is there a way how to create conditional NSDictionary? For example, lets assume there's a custom class with 3 properties:
class UserInfoObject
firstName
lastName
address
What I need is to create NSDictionary for non-nil properties out of userInfoObject. It straightforward when I know what properties are non-nil in advance, so I could use this shorthand syntax (or classic one):
NSDictionary *userInfoDic = #{#"firstName": userInfoObject.firstName, #"lastName":userInfoObject.lastName, #"address":userInfoObject.address}
However in my case, I need to create mutable dictionary and then perform manual check/add for each of the property. Is there another shorter way for doing below?
// Create mutable thing
NSMutableDictionary *userInfoDic = [NSMutableDictionary new];
// Check and add first name
if (userInfoDic.firstName) {
userInfoDic[#"firstName"] = userInfoDic.firstName;
}
// Check and add last name
if (userInfoDic.lastName) {
userInfoDic[#"lastName"] = userInfoDic.lastName;
}
// Check and add address
if (userInfoDic.address) {
userInfoDic[#"address"] = userInfoDic.address;
}
I had pretty much classes and properties, so shorthand (if exists) could facilitate the process :)

NSMutableDictionary already does this.
setValue:forKey: does this for a mutable dictionary:
This method adds value and key to the dictionary using setObject:forKey:, unless value is nil in which case the method instead attempts to remove key using removeObjectForKey:.
So, use setValue:forKey: instead of setObject:forKey:. There is no shorthand literal for this method. You could write your own NSMutableDictionary subclass and override setObject:forKeyedSubscript: to safely ignore nil objects, but it seems like too much work. As the documents say:
There should typically be little need to subclass NSMutableDictionary. If you do need to customize behavior, it is often better to consider composition rather than subclassing.
Take this to mean that you should, rather than subclass, create your own wrapper object that has an NSMutableDictionary as a backing store, and implements all the required methods to access the inner dictionary, overriding setObject:forKeyedSubscript: to work with nil. But I wouldn't recommend it just to avoid a few lines of code elsewhere.

Related

Assigning autoreleased object to a strong object

Lets say I have a class A with a member variable "myDictionary".
Now if I do this:
myDictionary = [NSDictionary dictionary];
I know that by default members of a class are of strong type. So myDictionary will be available during the lifetime of class A object. Thats what my understanding is about ARC.
But I am getting an EXE_BAC_ACCESS on myDictionary which really confuses me. Do I need to do anything extra in order to avoid EXE_BAD_EXCESS on myDictionary? Because above method returns an autoreleased object.
Thanks in Advance.
If you're not using ARC, then you should use +dictionary any time you
need an autoreleased dictionary, and +alloc/init any time you need a
dictionary that you're going to hold on to (e.g. by placing it in an
ivar), or alternatively if you simply want to avoid autorelease and
-release it manually.
So try to implement like this:
myDictionary = [[NSDictionary alloc] init];
The most likely error here is accessing myDictionary from multiple threads. Ensuring that you always access ivar correctly is one of the several reasons you should always refer to your properties as self.myDictionary rather than directly referring to the _myDictionary ivar. When you need to make this thread-safe, that will ensure there is only one place you need to fix the code.
There are other possible ways to get this error, such as incorrect handling of CFBridging... functions, but the most common is multi-threaded access.

#syntesize not working in xcode4.6

I am new to ios development and xcode.
Now i was taught that in xcode4.6 programmer doesn't need to use #synthesize statement as the IDE automatically does it for you.
However i don't know why my ide is not setting it then.
#property (nonatomic,strong) NSDictionary *dictionary;
and when i try to set something to it
dictionary = [[NSDictionary alloc]initWithContentsOfFile:resource];
it says undeclared identifier did you mean _dictionary. No i did not mean _dictionary i meant dictionary. So when i manually add synthesize property in implementation everything seems to be working fine.
Can somebody tell me what's going on in here.
The underlying instance variable for that property is in fact _dictionary. That is how auto synthesised properties work.
However you should consider using the accessors to set the property (using self.dictionary = instead). See this answer to "Reason to use ivars vs properties in objective c" for reasons behind this.
Also, consider changing the strong property to copy for classes like NSDictionary, NSArray and NSString to prevent mistakes where a mutable subclass (NSMutableString, NSMutableArray or NSMutableDictionary) is assigned to the property and then mutated.
#synthesize dictionary would have previously been written as #synthesize dictionary = _dictionary where _dictionary would be the variable related with the getters and setters generated by #synthesize.
It is safe to skip the = _variableName since XCode 4, but it will generate a variable matching the name of the synthesised attribute.
dictionary in your case, is only to be used as a setter and a getter, as [self setDictionary:object] or [self dictionary].
If you want to manually assign it a value, then you use _dictionary = object;
Be sure to understand that doing so is not KVC compliant. You will need to inform any observers that the value is about to change.
You forgot self.:
self.dictionary = [[NSDictionary alloc]initWithContentsOfFile:resource];
self.dictionary calls the setter method of the dictionary object, where as dictionary alone attempts to address a variable, either local to the function or an instance variable of the object. In your case you want to address the setter method.
_dictionary is equivalent to self.dictionary in Xcode4.6
This is to make sure that you are accessing the objects of the same current class.

Accessing obj as property vs method param (style preferences)

When it comes to accessing objects from different methods in the same class, from what I understand, these are two ways to do it. Given that I DO want to hold a property pointer to this object, which is the better way to go about this? I've been thinking about this for a while, and wondered if there is a preference consensus.
#1:
NSArray *array = ... // Get array from somewhere
self.myArray = array;
[self doSomethingToMyArray];
This method takes no parameter and accesses the array via its own property via self
- (void)doSomethingToMyArray
{
// Do stuff with/to the array via self.myArray
[self.myArray ...];
}
Vs #2:
NSArray *array = ... // Get array from somewhere
self.myArray = array;
[self doSomething:array];
This method takes an array and accesses the array via its own method parameter
- (void)doSomething:(NSArray *)array
{
// Do stuff with/to the array via method parameter "array"
[array ...];
}
I think it's primarily going to depend on what doSomethingToMyArray does and who calls it.
Fairly obvious comments:
if you want to do that to more than one array, you need to take an argument;
if what you're doing is actually logically more to do with the array than with your class (e.g. you've implemented randomisation of the order of the array) then it'd be better as a category on NSArray rather than being anywhere in that class at all;
if there's any possibility of subclasses wanting to redefine the manner in which the array is obtained then you'll want to invoke the getter somewhere;
similar concerns apply if a subclass or an external actor should be able to intercede anywhere else in the process.
Beyond those concerns there are a bunch of us that just prefer this stuff to be functional anyway — noting that you're doing something to the array, not with the array, in which case you'd tend more towards self.myArray = [self processedFormOf:array] (or self.myArray = [array arrayByDoingSomething]; if the category tip makes sense).
So, ummm, I don't think there's a clear-cut answer.
That depends on what you want to do, just by reading it:
doSomething:array
I would assume the above method takes ANY array and performs an action, whereas:
doSomethingToMyArray
with this method you are describing the intention of doing something to your instance's array. Inside this method (given that you followed Apple good coding practices and you synthesized your property to _myArray) , you could either go with:
[self.myArray message]
or preferably
[_myArray message]
Your second option is sort of silly. If you're storing a pointer in an instance, then it's so that you can use it later (within that instance) without needing to pass it around whenever you call a method.
This is also dependent on whether you're using ARC or not (use ARC if this is a new project). In a non-ARC project, self.myArray = foo; will do a very different thing than myArray = foo; (the self. syntax calls a property, which in many cases will correctly retain the thing you've assigned). In an ARC project, they'll generally have the same behavior, and there's less room for error.
Personally, in my ARC projects, I do not use the self. syntax from within a class, since it's just extra typing for the same effect. This ties in nicely with the new usage of #property, where you're no longer required to write a #synthesize block, and Objective-C will automatically generate an ivar for you, with the name of your property prefixed by an underscore, i.e. _myPropertyName. That makes it very clear visually when you're accessing code from outside the class (crossing the encapsulation boundary), where things will look like foo.bar = baz; versus inside the class, where it's just _bar = baz;.
IMHO, clearly, a function call would incur an extra overhead.
you would have to allocate an object pointer (though minimal) over the stack (extra memory)
Have to pass it (extra processing)
Property is actually a small function call unless you have made customizations to the getter. I also assume that compiler may have its own optimizations put in place for such accessors so that you can access them with minimal overhead, though I do not have any source to cite this.

NSMutableDictionary that retains its keys

I'm trying to figure out how to create an NSMutableDictionary that retains instead of copies its keys. I have implemented -(NSUInteger)hash and -(id)isEqual: for my desired keys, I am just having trouble figuring out which options to specify in the callbacks.
CFDictionaryKeyCallBacks keyCallbacks = { 0, NULL, NULL, CFCopyDescription, CFEqual, NULL };
self.commonParents = (NSMutableDictionary*)CFBridgingRelease(CFDictionaryCreateMutable(nil, 0, &keyCallbacks, &kCFTypeDictionaryValueCallBacks));
The above code works correctly in ARC for using weak references to keys, but what if I want strong references? What should the key callbacks look like?
tl;dr:
Create a CFDictionaryRef with the provided default callback functions. It'll do what you want. Just don't call it an NSDictionary.
Yes, you can create a CFDictionaryRef that retains its keys and does not copy them. This is, in fact, the default behavior of a CFDictionaryRef.
The documentation for CFDictionaryCreateMutable() says:
If the dictionary will contain only CFType objects, then pass a pointer to kCFTypeDictionaryKeyCallBacks as this parameter to use the default callback functions.
(So if you're only going to be putting normal Objective-C objects into the array and not random things like void * pointers or whatever, this is what you want)
And the documentation for kCFTypeDictionaryKeyCallBacks says:
Predefined CFDictionaryKeyCallBacks structure containing a set of callbacks appropriate for use when the keys of a CFDictionary are all CFType-derived objects.
The retain callback is CFRetain, the release callback is CFRelease, the copy callback is CFCopyDescription, the equal callback is CFEqual. Therefore, if you use a pointer to this constant when creating the dictionary, keys are automatically retained when added to the collection, and released when removed from the collection.
Note that the retain callback is CFRetain() and not something like CFCopyObject (which doesn't actually exist).
In fact, Core Foundation doesn't have a canonical way to "copy any object", which is why functions like CFStringCreateCopy, CFArrayCreateCopy, CGPathCreateCopy, etc exist.
So, what you can do is create your dictionary like this:
CFDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
And you now have a dictionary that retains its keys and does not copy them.
I'm going to put the following bit in big letters so that you grok what I'm about to say:
This dictionary you've created is not an NSDictionary.
Yes, NSDictionary and CFDictionaryRef are toll-free bridged. But casting this CFDictionaryRef to an NSDictionary would be an abuse of that bridging, because of this line in the NSDictionary documentation:
...a key can be any object (provided that it conforms to the NSCopying protocol—see below)
Similarly, the documentation for -[NSMutableDictionary setObject:forKey:] explicitly says:
The key is copied (using copyWithZone:; keys must conform to the NSCopying protocol).
The keys in your dictionary don't have to conform to <NSCopying> and are not copied using -copyWithZone:, which means your dictionary is NOT an NSDictionary (or NSMutableDictionary). Any time you see NSDictionary used in code, you should be providing a key-value map where the keys are copied (not retained). That is the API contract. To do anything else could result in undefined behavior.
(The fact that some objects override -copy to return [self retain] is an implementation detail and is not relevant to this discussion on "what is an NSDictionary".)
I think the best answer is buried in comment, so I'll highlight it here: The simplest approach is to use a +[NSMapTable strongToStrongObjectsMapTable] (or maybe one of the variants with weak references).
My suggest is that instead of doing this you subclass NSString or whatever class you're using as key, and override the copy method in a way that it returns the string retained, instead of a copied string.
I think there is 2 possibles solutions that could be achieved using plain old NSMutableDictionary. They are not as elegant as NSMapTable would be.
You state that each of your Key have a uniqueID, so I assume that this Value won't change over time.
Option 1 :
Use the uniqueID of your actual key to be the key of an NSMutableDictionary that would store NSArray of #[key, value] so the whole structure look like this
#{ key1.uniqueID : #[key1, value1], key2.uniqueID : #[key2 : value2] }
Option 2 :
Make a subclass of NSObject that is a wrapper around option 1. Or any variation on option 1.
Those are only valid if uniqueID never change

NSUserDefaults and primitive data types?

What is the point of the NSUserDefaults methods such as -setFloat:forKey: and -floatForKey: when -registerDefaults: accepts only a NSDictionary which can't hold any primitive data types - only objects.
Instead it seems I have to use -setObject:forKey and -objectForKey: and store only NSNumber objects if I want to be able to give my floats any actual default values.
What am I missing here?
setFloat: is just a convenience method that creates an NSNumber and then passes that to setObject:. floatForKey: does the reverse.
NSDictionary can only hold object types, so you need to wrap primitives in the appropriate objects. So yes, you do need to do what you are doing to set up the default defaults.
It would be nice if you could use those methods directly on an NSDictionary, that would be a pretty trivial category to write.

Resources