Why Do I Have to Create An Object and Assign It to A Property in Objective C? - objective-c

So I had this code, and it did not work:
for (NSDictionary *item in data){
[self.resultsArray addObject:item];
}
self.resultsArray is nil. But then I changed it to this:
NSMutableArray *myDataArray = [[NSMutableArray alloc] init];
for (NSDictionary *item in data){
[myDataArray addObject:item];
}
self.resultsArray = myDataArray;
[myDataArray release];
and now it worked. self.resultsArray is now populated
So I'm a beginner in Objective C and I was wondering why can I not just directly use it in the property's addObject. Why did I have to create another mutable array, populate it, assign it to the resultsArray property and release the mutable array I made?
Thanks in advance!
EDIT: Also, in a lot of books I've been working on, this is done a lot.

simple answer
You didn't initialize self.resultArray before adding objects to it. It is just a pointer to the value which is nil until you alloc it.
self.resultArray = [[NSMutableArray alloc] init]; before adding objects to it will solve the issue.
However, this way of alloc'ing will create a memory leak, therefore it is not shown in books and examples. Memory leak can happen if the self.resultArray property is marked as retain and by calling alloc it will be retained 2 times.

If self.resultsArray is nil, then [self.resultsArray addObject:item] will NOT add an object to the array, it will just do nothing (because the array will be nil by default, and sending messages to nil is a no-op in Objective-C). When you create a mutable array as a local variable, you can add things to it — then if you assign it to the property, well, everything works as you expect and self.resultsArray will no longer be nil.
Typically when you have properties like this, you'd set them up in your init method:
- (id)init {
// ...
self.resultsArray = [NSMutableArray array];
// or access the ivar directly:
// _resultsArray = [[NSMutableArray alloc] init];
// ...
}
Then as soon as your object is initialized you'll be able to add things to the array. Again, if you don't do this, it will be nil by default, and [self.resultsArray addObject:item] will have no effect.

Chances are you are not initializing the array (I'm going to assume myDataArray is an NSMutableArray).
In your init method, call myDataArray = [NSMutableArray array]; and it'll work

The important thing to note is that you're not creating another mutable array as you didn't have an array to start with. Merely declaring a property or variable does not create an object to go along with it. That's why self.resultsArray starts out as nil.
The working code you have is designed to allow you to explicitly release the array as you are retaining it twice: once when you alloc it and once when you assign it to your property. You only want one of those retains, so you release once.
You could just do:
self.resultsArray = [[NSMutableArray alloc] init];
[self.resultsArray release];
for (NSDictionary *item in data){
[self.resultsArray addObject:item];
}
This is less code, but it's not as clear. Clarity is important.

Related

correct way to allocate the NSMutableArray

I wanted to know which is the right way to allocate an NSMutableArray.
NSMutableArray *a;
Where a is a class level variable.
First method is:
self.a = [NSMutableArray alloc] init];
Second method is:
a = [NSMutableArray alloc] init];
Which method is better? Can anyone please help me out in this?
If a is a class variable, then correct way to allocate NSMutableArray will be creating a temporary array and assigning it to class variable, followed by releasing the temporary variable.
You can do this way:
NSMutableArray *temp = [[NSMutableArray alloc]init];
self.a = temp;
[temp release];
It depends on the property type. (Though it's in most cases a retain)
You should either use a temp value or create it in one string and send an autorelease message:
self.a = [[NSMutableArray alloc] init] autorelease];
You must send an autorelease becuase a property increases retain count by one. This is the same as doing:
[self setA:array];//where array - is newly created array
Where:
- (void)setA:(NSMutableArray *)array {
if (array != a) {
[a release];
a = [array retain];//here you increased a retain count by 1
}
}
You can also use an autorelease method of creation:
self.a = [NSMutableArray array];
There are several ways. But below way is good enough per me whether you are working with ARC/Non-ARC. Just make sure you have created property.
self.a = [NSMutableArray array];//It will return autorelease object.
The difference between the methods:
1) When you use self.a ,
You use the setter & getter methods created in the #synthesize.
2) When you use just a,
You bypass the accessor methods and directly modify the instance variable. (a in here).
There are two ways to look at it.
Many programmers say that you should never call the accessors from within the implementation of the object as this adds unnecessary overhead.
Some others say that you should always use the accessors, and never access the instance variable directly.
It is generally safe to use an object directly, if you are reading its value only. If you are modifying the object, you should use the accessors in order to make sure that any other objects observing that property are properly notified.
The latest objective C syntax allows you to create mutable and non-mutable arrays very quickly.
The following two examples demonstrate this:
NSArray *objectsToAdd = [#"Ted", #"Ned" , #"Sed"];
NSMutableArray *objectsToAdd = [ #[#"Ted", #"Ned" , #"Sed"] mutableCopy ];
NSMutableArray *a = [[NSMutableArray alloc] init];

Cannot add items to an NSMutableArray ivar

My goal is to add a string to array, and I do that in a method which I call.
In this method, I get a null value in the array, and don't know why. I have this at the start of my class:
NSMutableArray *listOfEvents;
and a method which I call on each event:
-(void)EventList
{
[listOfEvents addObject:#"ran"];
NSLog(#"%#", listOfEvents);
}
I get (null) in the log.
If I put the array definition NSMutableArray *listOfEvents; in the function body, I get the string value #"ran", each time, so the array always has only one value, instead of having many strings named #"ran".
What's wrong with this? It seems that I can't understand something about arrays, even though I have read the documents a number of times.
I'm assuming you haven't initialized listOfEvents.
Make sure you do listOfEvents = [[NSMutableArray alloc] init]; in your class's init method. Also make sure you release it in your class's dealloc method.
If you're getting nil in your log message, you need to make sure listOfEvents is non-nil before adding your object. IE:
-(void)EventList
{
if (listOfEvents == nil) {
listOfEvents = [[NSMutableArray alloc] init];
}
[listOfEvents addObject:#"ran"];
NSLog(#"%#",listOfEvents);
}
In Objective-C, messages with void return types sent to nil go to absolutely-silent nowhere-land.
Also, for the sake of balance, be sure you have a [listOfEvents release] call in your dealloc implementation.
Apparently you're not initializing your array.
NSMutableArray *listOfEvents = [[NSMutableArray alloc] init];
If that's your problem, I suggest reading the docs again. And not the NSMutableArray docs. Go back to The Objective-C Programming Language and others.
You need to alloc the NSMutableArray. Try doing this first -
NSMutableArray *listOfEvents = [[NSMutableArray alloc] init];
After this you could do what you what you planned...

Garbage Collection question in Cocoa

I have the following code in a Cocoa program. In this code, theList is a pointer to an NSMUtableArray object and input is an NSTextField pointer.
-(IBaction)addItem:(id)sender
{
NSString *item = [input stringValue];
[theList addObject:item];
. . .
}
When the program runs and this method is called, I get an access violation on the line
[theList addObject:item]. As a last resort, I turned garbage collection on and the code works without any problem. I don't understand why it doesn't work without the garbage collector. Can someone explain? Thanks
You probably didn't initialize your array correctly. It's common to see people
initializing ivars with autoreleased objects:
- (id)init
{
self = [super init];
if (self) {
array = [NSMutableArray array];
}
return self;
}
This won't work. When your method is called no-one guarantees that the array
still exist. Turning the garbage collector on will leave the memory management
task with it, which understands that you want to use the array later and
manages it correctly.
Under traditional memory management rules, use something like this:
array = [[NSMutableArray alloc] init];
Please post your code, where the array is initialized.

simple NSMutable array question

umm So simple question here:
I have an instance of NSMutableArray declared in my header
NSMutableArray *day19;
#property (nonatomic, retain) NSMutableArray *day19
implementation:
#synthesize day19;
In my viewDidLoad
self.day19 = [[NSMutableArray alloc] init];
In the myMethod where I want to add objects to the array I:
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
However... when i check the day19 array there is nothing in it. If I conversely add the newObject to a tempArray within the myMethod scope and then set the day19 array to the tempArray, day19 has the objects.
Super basic I know just must be a confused morning or something...
thanks for any help
Is day19 actually an instance variable? In the snippet, it's not clear when it's declared as an instance variable or just as a variable outside the scope of the class.
A couple of things:
Are you sure viewDidLoad is the right place to init your array? Confer here.
Also, at least from the code you've got posted, it looks like you're being sloppy with your retains. If your property is a retain type, you should not be writing:
self.myProperty = [[Something alloc] init]; // double retain here, bad
You should instead be writing something like:
self.myProperty = [[[Something alloc] init] autorelease]; // single, good
Also, with
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
unless you have a
[newObject release];
down the pike, you've got a memory leak.
In my viewDidLoad
self.day19 = [[NSMutableArray alloc] init];
In the myMethod where I want to add objects to the array I:
NSObject *newObject = [[NSObject alloc] init];
[day19 addObject:newObject];
However... when i check the day19 array there is nothing in it. If I conversely add the newObject to a tempArray within the myMethod scope and then set the day19 array to the tempArray, day19 has the objects.
Let me guess: You checked the array with code like this:
NSLog(#"day19 contains %lu objects", [day19 count]);
Remember that a message to nil does nothing and returns nil, 0, or 0.0. That's why the output said 0 objects: You don't have an array in the first place. The most probable reason for that is that viewDidLoad hasn't been called yet, so you have not yet created the mutable array.
It's also possible that you have an array (i.e., the view has been loaded) at the time you examine the array, but you didn't have an array yet (the view hadn't been loaded yet) at the time you tried to add to the array, so your addObject: message fell on deaf ears.
Consider creating the array earlier. You probably should be creating it in init or initWithCoder:.
A third possibility is that you examined the array before you ever added to it. Make sure you log or break at both points, so you know which one happened first.
Whatever the problem is, you also need to either assign the array to the instance variable, not the property, or autorelease the array before assigning it to the property. Otherwise, you're over-retaining the array, which means you will probably leak it later on. You probably need to review the Memory Management Programming Guide for Cocoa.

Deallocating NSMutableArray of custom objects

I need help with deallocation of my NSMutableArray of custom objects. I need to retain the array and so I have added a property in .h and I release it in dealloc in .m file. When I add objects to the array, I do the following:
myarray = [[NSMutableArray alloc] init];
[myarray addObject:[[mycustomObject alloc]initWithObject:obj1]];
[myarray addObject:[[mycustomObject alloc]initWithObject:obj2]];
Now, I don't know how to release mycustomobject. If I do the following:
[myarray addObject:[[[mycustomObject alloc]initWithObject:obj1] autorelease]];
I run in to problems when I access the array later. Please advice.
I don't think you understand how memory management in Cocoa works. The array will retain the objects you add to it, and it will release them by itself when the array no longer needs them (such as when you release the array).
In other words, add the autoreleased object to the array, and don't worry about its retain count after that. If you want to remove it from the array simply remove it (using removeObjectAtIndex: or something similiar). If you think you want to release the object without removing it from the array then you are doing something wrong, since that may leave a dangling pointer in your array that will cause you to crash later.
You should really really go over the documentation again, particularly the section on Object Ownership and Disposal.
The proper way to do this is to let the array maintain ownership of the custom object:
NSMutableArray * array = [[NSMutabelArray alloc] init];
for (id obj in anArrayOfObjects) {
mycustomObject * customObj = [[mycustomObject alloc] initWithObject:obj];
[array addObject:customObj];
[customObj release];
}
If you're having difficulties accessing your array later, then you're doing something wrong with the memory management of the array.