Assigning values to Instance variables in Objective C
-
22-08-2019 - |
Question
The function I'm looking at:
-(void)viewDidLoad {
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:@"statedictionary" ofType:@"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.statesZips = dictionary;
[dictionary release];
NSArray *components = [self.stateZips allKeys];
NSArray *sorted = [components sortedArrayUsingSelector:@selector(compare:)];
self.States = sorted;
NSString *selectedState = [self.states objectAtIndex:0];
NSArray *array = [stateZips objectForKey: selectedState];
self.zips = array;
}
Why is an NSDictionary allocated, then assigned to a pointer called *dictionary, and then assigned to the instance variable stateZips? Why not allocate it and assign it directly to the instance variable and save memory of creating and releasing another NSDictionary? The same methodology is always followed, including later in this function with the NSArray...
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.statesZips = dictionary;
[dictionary release];
Also, this sorting puts the keys from a hash table (dictionary) in alphabetical order. I'm not sure I understand this line:
NSArray *sorted = [components sortedArrayUsingSelector:@selector(compare:)];
Solution
No one seems to have addressed the fact that the line
self.statesZips = dictionary;
is not directly an instance variable assignment. stateZips
is a property, and so that line of code calls the setStateZips:
method. That method retains or copies the dictionary, so unless the viewDidLoad
method intends to use it again for some purpose, it's not needed any longer. That makes it OK to release
it.
The previous line:
[[NSDictionary alloc] initWithContentsOfFile:plistPath];
allocates an object. That makes it your responsibility to release
it once you don't need it any more. After assigning it to the statesZips
property, it's no longer needed, so it's released and you shouldn't use dictionary
any more. You'll notice that later code only refers to self.stateZips
, not dictionary
.
In the case of the NSArray
later in the method, viewDidLoad
does not allocate the object, so that method is not responsible for calling release
on it. The rule of thumb is that if you alloc
it, you're responsible for making sure it gets released. Otherwise, it's not your problem.
Sorting the array uses the sortedArrayUsingSelector:
method. A selector identifies a method in Objective-C. And the @selector
is the literal syntax for selectors (kind of like how @""
is the literal syntax for NSString
objects). So, what that code says, is "give me an array where the objects in components
are sorted, and use the compare:
method to compare each object when you do the sort. When it sorts the array, it will call compare:
on the objects in the array to determine how to put them in order.
OTHER TIPS
The statesZips
property is probably retained, that's the reasoning.
When the NSDictionary is first allocated, its retain count is 1. When it's assigned to statesZips, the retain count becomes 2. When it's released, the retain count drops to 1, which is usually the desired outcome.
Note that the code below would have produced (almost) the same result:
self.statesZips = [NSDictionary dictionaryWithContentsOfFile:plistPath];
because dictionaryWithContentsOfFile
returns an autoreleased object.
As a convention, class methods like [NSDictionary dictionary]
return autoreleased objects (which automatically get released after some time), while the usual alloc-init method (as in [[NSDictionary alloc] init]
) return retained objects.
I suggest you read the Memory Management Programming Guide for Cocoa for further information.
EDIT: I must have missed the last part of your question when I first read it, but Barry has already answered that part.
This code uses reference-counted memory management (not the automatic garbage collection memory management available in Objective-C 2.0 on OS X). When any object (in this case, the NSDictionary and the NSArray) are alloc'd, the caller is responsible for calling -release
on that instance. Failing to call release causes a memory leak. The code could have been written as
self.statesZips = [[[NSDictionary alloc] initWithContentsOfFile:plistPath] autorelease];
but at the expense of less explicit memory management (relying on NSAutoreleasePool
to release the alloc'd instance at the end of the event loop iteration.
the call
[components sortedArrayUsingSelector:@selector(compare:)];
returns an array of whose elements come from components
but according to the return value of calling [elem1 compare:elem2] to compare two array elements.