Is myiVar = nil supported in ARC? - objective-c

I'm using a code snippet like
if ([Array count] != 0) {
Array = nil;
}
Array = [[NSMutableArray alloc]init];
Is this allowed when using ARC? Does this cause any kind of crashes? Why I'm doing this is each time when my method gets called Array gets a new set of data. I'm using this kind of snippet in many places of my class.

ARC aside, the operation is pointless. You assign an ivar to nil then immediately assign to something else. This is no different from just assigning it to the something else.
Before ARC this would have given you a memory leak (with or without your assignment to nil) if there variable had a previous value. With ARC there is no leak.

Best solution : test and see by yourself ! This is a really short example !
But yes, this works of course !
ARC means Automatic Reference Counting. It just says you don't have to care about release, retain and so on.
If you want an object to be nil, you still can, as it is a simple pointer assignment !
And about your code, you set Array to nil before re-assigning it oO !
Try to get the logic of your code :
If my Array has objects
Then Array point to a new nil object
But in all case you do:
My Array point to a new NSMutableArray object
So whether or not your condition is evaluated to true, your code is useless as the variable will take another value just after !

The sample code you showed is valid. Here are a few variations:
if ([Array count] != 0) {
Array = [[NSMutableArray alloc] init];
}
Example 2:
if ([Array count] != 0) {
Array = [NSMutableArray array]; //value will be retained
}
Example 3:
if ([Array count] != 0) {
self.Array = [[NSMutableArray alloc] init]; //Will NOT leak under ARC.
}
Example 4:
//if ([Array count] != 0) {
[Array removeAllObjects];
//}
All four examples are valid under ARC.
Another thing: instance variables typically have their first letter lowercase, while still following the CamelCase method. Another way to do it is to have an underscore before the name of the variable: this is done if you don't have a #synthesize method to match your #property value.

Related

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.

Why Do I Have to Create An Object and Assign It to A Property in 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.

Issue with NSMutableArray visibility / retain

Alright so I am a little new to the NSMutableArray class and I think I am missing something obvious. I have an object pass a NSMutable Array to my window controller like so in my.m:
summaryWindow = [[SummaryWindowController alloc] init];
[summaryWindow setGlobalStatusArray:globalStatusArray];
I have the receiver method in the summaryWindow object as so:
-(void)setGlobalStatusArray:(NSMutableArray *)myArray
{
if ([myArray count] >0) {
if (globalStatusArray) {
[globalStatusArray release];
}
globalStatusArray = [[NSMutableArray alloc] initWithArray:myArray];
NSLog(#"Summary Window Init with new array: %#",globalStatusArray);
I see the NSLog no problem, and in that same object (summaryWindow) I have the following method:
- (NSMutableArray *)getGlobalStatusArray
{
return globalStatusArray;
}
Now I have globalStatusArray declared in my .h file as
NSMutableArray *globalStatusArray;
So shouldn't This be retained because I am using: initWithArray?
When I try to access this value in an another IBAction method:
- (IBAction)refreshButtonClicked:(id)sender
{
NSLog(#"The user has clicked the update button");
[ aBuffer addObjectsFromArray: globalStatusArray];
NSLog(#"Buffer is currently:%#",aBuffer);
[tableView reloadData];
}
The NSMutable array is null
2011-08-18 10:40:35.599 App Name[65677:1307] The user has clicked the update button
2011-08-18 10:40:35.600 App Name[65677:1307] Buffer is currently:(
)
I have tried using my own method to get the value i.e. [ self getGlobalStatusArray] to but I am missing something huge. FYI aBuffer is also declared in my .h ,
As albertamg noted, that looks like an empty array rather than nil, and a released object doesn't magically become nil under normal circumstances anyway.
This smells strongly of two different objects. Try logging self in your methods and see if one instance is getting the array and another is interacting with the UI.
This code isn't doing anything useful:
if ([myArray count] >0) {
if (globalStatusArray) {
[globalStatusArray release];
}
globalStatusArray = [[NSMutableArray alloc] initWithArray:myArray];
If the count of the old array is zero, it's leaking the actual array object. If the count is not zero, then it's releasing it properly. Just do the release and don't bother counting.
Are you sure there's actually something in myArray?
joe

NCSFDictionary, Mutating method sent to immutable object

I have just started to jump into the realm of Objective-C and am slowly getting it all. I have been working on unarchiving a file that was a NSMutableArray and then initializing in my model with that array. The array is filled with various NSMutableDicationary's. From what I have seen it will add those dictionaries as non-mutable, so I went ahead and copied the regular and put them in a mutable and remove the old one. This solution seems to work for every instance except the very first.
I am at a loss as to why it would work for all but the first.
Here is how I am initializing it all
-(id) initWithList:(NSMutableArray *)savedList
{
self = [super init];
if (self)
{
int size=0;
serverList=[[NSMutableArray alloc] initWithArray:savedList copyItems:YES];
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
}
return self;
}
Here is the code that is throwing the error, The value is being read off of a checkbox in a tableview and passed here to change the value.
-(void)setMount:(int)row value:(NSNumber*)boolAsNumber
{
[[serverList objectAtIndex:row] setObject:boolAsNumber forKey:#"mountshare"];
}
Here is the error that it shows when I try and change the first element
2010-12-01 13:38:54.445 Network Share[35992:a0f] *** -[NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Thanks for your help. If there is a better way please let me know.
This loop code is wrong:
size=[serverList count];
for(int i=0;i<size;i++)
{
loginList=[NSMutableDictionary dictionaryWithDictionary:[serverList objectAtIndex:i]];
[serverList addObject:loginList];
[serverList removeObjectAtIndex:i];
}
When you remove an object, the array is renumbered. After you've processed the 1st object at index 0, the original 2nd object is becoming the 1st object at index 0, but i is now set to index 1, which is where the original 3rd object is! This means you're only processing alternate items from the original array, and the 2nd, 4th, etc items never get swapped, and that's why you get the errors you're seeing.
One way to solve this would be to replace the "i" in the objectAtIndex: and removeObjectAtIndex: calls with "0", so you're always taking items off the front of the array.
The alternate solution would be to create a separate newServerList array and insert your new objects into that. At the end of the loop, release the old serverList and set the variable to point to newServerList.
Your indexes are messed up. As soon as you remove the object at index 0, the next one will take it's place and you will never replace that, because you then carry on with index 1.
{immutable0, immutable1}
i = 0:
addObject:
{immutable0, immutable1, mutable0}
removeObjectAtIndex:
{immutable1, mutable0}
i = 1:
addObject:
{immutable0, mutable0, mutable02}
removeObjectAtIndex:
{immutable0, mutable02}
--> still got the immutable there. Remember to never remove objects from a mutable array you are looping through at the same time.
You could condense the code a bit:
NSMutableArray *serverList = [NSMutableArray arrayWithCapacity:[savedList count]];
for (NSDictionary *dictionary in savedList)
{
mutable = [dictionary mutableCopy];
[serverList addObject:mutable];
[mutable release];
}
Unrelated to your problem: the argument is obviously wrong (NSMutableArray), if you expect an immutable array there; and if you create your serverList that way, there is no need for a deep copy (copyItems:YES).