How to manage memory for autorelease objects - objective-c

I work on implementation of playing card class and i've created the following method:
+ (id)cardWithCard:(Card *)newCard
{
Card *card = [[[Card alloc] initWithCard:newCard] autorelease];
return card;
}
i use autorelease method here cause otherwise Product->Analyze warns me about potential leak. Everything works fine until variable myCard (which was allocated earlier) to which a new value was assigned like this:myCard = [Card cardWithCard:newCard] is sent to a different method as a parameter. It turns out to be deallocated there and my app crashes.
How should i resolve this issue? Get autorelease method away despite warnings of Analyze?

Each method or object should be responsible for retaining object that it is interested in.
It it easier to maintain. (Exception are for method that have alloc, new or copy in there name, they will return an object that the caller is responsible to release.)
So you need to keep the autorelease because that method don't exist after the return and won't be able to call release on it.
The Object that is calling cardWithCard should retain the object if it want it to be alive more that the time of that particular method.
The code should look something like this
self.myCard = [Card cardWithCard:newCard];
This is in the case where myCard is declare like this
#property (nonatomic, retain) Card * myCard;
So in this case the property will do the retain for you and will release that object when you will place a new one in this property. (If you overwrite the auto-generated accessor, you will need to manage that yourself in those method)
If for some reason you don't want to use a property... well it's your choice :-)
You will need to do something like this:
myCard = [[Card cardWithCard:newCard] retain];
and you will need to something like this later on
[myCard release];
If it's not in the same method the analyser will compline, and if it's in the same method you probably don't need the retain.

Related

Malloc error in Objective C

Right now in my application there is a producer that outputs an array of data; the output from that producer is bound (using the "Bindings" in the XIB file) to a Table View in my window. The producer spits out data, and it shows up in the window, all is well.
Except that I need to modify the data being shown. The producer is a third-party app, so I can't modify it directly, so I need to create a filter object that sits between the two.
The object I created looks like this:
#interface testFilter: NSObject {
id output;
}
-(void)setInput:(id)s;
#end
I changed the binding so that the output from the producer goes to my input:
[myFilter bind:#"input" toObject:producer withKeyPath:#"output" options:0];
and my implementation looks like this:
-(id)init
{
self = [super init];
output = nil;
return self;
}
- (void)setInput:(id)newInput
{
int nEntries = (int)[newInput count];
id copiedArray = [NSMutableArray arrayWithCapacity:3];
for (id entry in newInput)
{
id copiedEntry = [entry mutableCopy];
// blah blah make some changes to copiedEntry
[copiedArray addObject:copiedEntry];
[copiedEntry release]; // I'm done with it, copiedArray added his own retain
}
[self setValue:copiedArray forKey:#"output"];
[copiedArray release]; // I'm done with it, setValue/output added a retain
}
But this is crashing with the error:
"malloc: *** error for object 0x108e00870: pointer being freed was not allocated"
...until I remove the [copiedArray release] line.
Am I wrong in thinking that I should be sending [copiedArray release]?
What else can I check / what is the recommended way to debug problems like this?
id copiedArray = [NSMutableArray arrayWithCapacity:3];
This will create an autoreleased object. You shouldn't release autoreleased objects.
Either remove your release call, or change that line to this:
id copiedArray = [[NSMutableArray alloc] initWithCapacity:3];
That being said, consider using Automatic Reference Counting (ARC).
From Advanced Memory Management Programming Guide:
You own any object you create
You create an object using a method whose name begins with alloc,
new, copy, or mutableCopy (for example, alloc, newObject, or
mutableCopy).
You can take ownership of an object using retain
A received object is normally guaranteed to remain valid within the
method it was received in, and that method may also safely return the
object to its invoker. You use retain in two situations: (1) In the
implementation of an accessor method or an init method, to take
ownership of an object you want to store as a property value; and (2)
To prevent an object from being invalidated as a side-effect of some
other operation.
When you no longer need it, you must relinquish ownership of an object you own
You relinquish ownership of an object by sending it a release
message or an autorelease message. In Cocoa terminology,
relinquishing ownership of an object is therefore typically referred
to as “releasing” an object.
You must not relinquish ownership of an object you do not own
This is just corollary of the previous policy rules, stated

returning an nsmutuableArray as a pointer that is an mutuablecopy

I dont want to return manch because if i autorelease before i return it ,it becomes invalid to others. so i was thinking of this :
classA
-(NSMutableArray*)set:(NSMutableArray*)data
{
manch= [[data mutableCopy]autorelease] ;
int count=2*[data count]; //to not enter infinity loop
for(int k=0;k< count;k=k+2)
{
if(k==count-1)
[manch addObject:[NSNumber numberWithInt:![[manch objectAtIndex:k] integerValue] ] ];
}
data=[manch mutuableCopy];
return data;
}
My goal is to create a class that gets an NSMutuableArray do some calculations, than return it, and NOT TO BE DEPEND on this class anymore .
EDIT :
As people here ask.
in another classB(the user of the method above), i have in the interface :
NSMutuableArray *data ;
and on the .m file init method i have
data=[[NSMutuableArray alloc]init];
to use the function from my question, i do :
mIns=[[classA alloc]init];
data= [mIns set:[self decimalToBinary:autoWord]];
than i loose data later.
I dont want to return manch because if i autorelease before i return it ,it becomes invalid to others. so i was thinking of this:
This is an incorrect statement, you can return an autoreleased object, that's a sane thing to do. It's worth noting that you should design your method names correctly to inform the user what sort of object is returned. Any method whose name begins with alloc, new, copy, or mutableCopy will return a retained object. (Source)
In your case, your method name is set:, which informs the user of this method that it will return a non retained object (almost always an autoreleased object). This is because it isn't prefixed with any of those words mentioned above.
In that case, the issue you have is with the user of the method; they are not retaining a reference to the object being returned. As such, the user of the method should use it as so:
#interface ClassName () {
NSMutableArray* m_ivarArray;
}
#property (nonatomic, retain) NSMutableArray* propertyArray;
#end
NSMutableArray* data = ...;
// If using a property with retain, setting via "self." will retain it for you
self.propertyArray = [self set:data];
// If using an ivar (which doesn't do the retain for you)
m_ivarArray = [[self set:data] retain];
You can avoid these issues by using Automatic Reference Counting (ARC, More Information), which will handle this sort of memory management for you. It is still important that you use the correct naming conventions, as ARC will judge how to manage your memory based on this (in certain situations)
Update: After seeing your update, I can see the problem.
data=[[NSMutuableArray alloc]init];
This is creating a new instance of NSMutableArray, one which is correctly retained (due to what I mentioned before).
data= [mIns set:[self decimalToBinary:autoWord]];
This is replacing the object held in data with a new NSMutableArray, one that is autoreleased. The previous instance you created has been lost, and you've replaced it with another one. This new instance has not been retained, and as such, will be released unexpectedly.
To fix, you need to use this instead:
NSMutableArray* data = [[mIns set:[self decimalToBinary:autoWord]] retain];
You don't need to alloc/init a variable if it will be populated by some other object later on. I strongly suggest brushing up on how this all works, this might be a good start.

Releasing a pointer causes program to crash, even though the variable isn't used

I'm still slogging through learning memory allocation and Objective-C (my first run with Leaks was unpretty, at best). Here is a current issue, I hope everyone can understand it, I've used some pseudo-code, but I don't believe I've left anything out.
I have a Row Class set for some database stuff, we'll use this:
#interface Row : NSObject {
int rowID;
NSString *firstName;
NSString *lastName;
}
I have a getRow function in my database class that looks something like this:
-(Row *) getRow
{
rowPlaceholder = [[Row alloc] init];
...
rowPlaceholder.rowID = column1;
rowPlaceholder.firstName = column2;
rowPlaceholder.lastName = column3;
...
return [rowPlaceholder autorelease]; //<-----Problem is happening here
}
Now in my ViewController I have 2 functions of importance to this situation:
-(void) viewWillAppear:(BOOL)animated{
currentRow = [[Row alloc] init];
currentRow = getRow;
firstNamelabel.text = currentRow.firstName;
}
The second function is a button the gets the second word:
-(IBAction)btnLastName:(id)sender{
lastNamelabel.text = currentRow.lastName; //<---Crashes the program
}
So, as you can see, using currentRow against causes the program to crash, and what I can't understand is that if I don't release rowPlaceholder the program works fine. At this point why does currentRow care about the data from another function, since it already has what it want (a value from getRow()).
What's going on here?
currentRow = [[Row alloc] init];
currentRow = getRow;
You create a row, then overwrite it with... I don't even know what getRow is in this context. There's no way this is compiling without warnings. Anyway, try using:
currentRow = [[self getRow] retain];
(Although, for the sake of convention, you should call the method just row.)
Without seeing the rest of your getRow method or Row class, I can't tell why the problem would be happening there.
autorelease means that the object in question will be automatically released. When this occurs is tied to when the autorelease pool is emptied, but for the default case it's when the UI "comes up for air" -- when your call chain returns back to the UI system code. If you're going to hold something "across" such a return to UI system code, you need to have it explicitly retained. In general, making it a retained property is the best way to do this (though of course you need to clear/release the property in your dealloc method).
[And why do you do this:]
currentRow = [[Row alloc] init];
currentRow = getRow;
When you allocate and init rowPlaceholder and then return it as autoreleased, that means its effectively ready to be cleaned up by memory management unless some other object retains it.
In the line:
currentRow=getRow
you are getting a copy of the pointer to the object returned by getRow but do not appear to be retaining it. (and getRow is autoreleasing it before returning it).
If currentRow is a property of your class then you need to refer to it as this.currentRow to ensure the accessor method is called (and it must be declared as a retain property). if its not declared as a property and is just an attribute of your class then you need to retain it manually.
The first time you reference currentRow.firstName is ok because there has been no loss of control by the current execution thread so the autorelease pool hasn't cleaned up this memory yet.
But once your thread loses control and give memory management a chance to clean it up, when you come back into the the btnLastName method the memory pointed to by currentRow (which is a pointer to the original memory allocated in the rowPlaceHolder = [[row alloc] init] call) has been released.

Objects creation and instantiation in objective-c

Given the piece of code below where blueViewController is an iVar.
Question: Why not instantiate the iVar directly?
BlueViewController *blueController = [[BlueViewController alloc]initWithNibName:#"BlueView" bundle:nil];
self.blueViewController = blueController;
[blueController release];
It depends on where you are in your class. If you are in your init (and dealloc) method it is recommended to refer to the ivar directly to avoid any side effects in setter logic. Therefore in the init I would do
_blueViewController = [[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil];
But anywhere else I would do it how you have done it. Then if there is any custom logic in the getter/setter I know it will be run.
To eleborate on #Vladimar's point the synthesized setter for a retain will do some memory management similar to this:
- (void)setMyObject:(MyObject *)newMyObject
{
// If it's the same object we don't need to do anything
if (_myObject != newMyObject) {
[newMyObject retain];
[_myObject release];
_myObject = newMyObject;
}
}
It is much safer to let the getters/setters worry about all this logic any time you set your ivars.
You can initialise iVar directly, but the code you have also handles memory management for the previous blueViewController value. Accessing iVar directly you'll have to release previous value manually before assigning new one.
You can do it all on one line if you want. The important thing is to balance the +alloc with a -release or -autorelease. So, you can say:
self.blueViewController = [[[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil] autorelease];
That's fine, but some folks prefer to avoid -autorelease, and some folks just prefer simpler steps and/or shorter lines of code. Using an intermediate variable as you've done helps in that respect, and it doesn't cost anything.
It depends on whether the property is retain or not. Most object properties are retained; this is what a retain property looks like:
- (void)setBlueViewController:(BlueViewController *)bvc {
if (bvc != blueViewController) { // blueViewController is local ivar
[blueViewController release];
blueViewController = [bvc retain];
}
}
So what you're doing up there is creating a retain count of +2. When you init, that's a +1; the property then retains it, bumping it up to +2. Your dealloc releases it once, which brings it down to +1...and you've leaked that property. Because you are alloc/init-ing the variable, you don't want to use the setter; instead, assign it directly to the instance variable.
By instantiating it directly, it saves you the trouble of that other release—fewer lines of code means fewer errors. You might, for example, have typed retain by accident and not realized it until your program crashes because you retained a massive class...
Of course, as Caleb says you could autorelease, but that's effectively letting the object lie around in memory until the run loop is finished. It's much easier, and gives you more control, to just not worry about that. There's nothing wrong with assigning the alloc/init to the ivar; in fact, that's the best way to do it.

Balance retain with release?

I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
gary
No, but you shouldn't need to do this at all since you are not allocating anything. You could simply return name and that should be fine. Was there a reason you needed to add this retain/autorelease?
A little more explanation, what is happening here is that your retain count goes up by one when you do a retain, and then down by 1 when the scope exists because of the autorelease.
I don't know how your variable definition is in your class but the rule is that in your getter you should return the object unchanged for the reference count. It's the responsability of the caller to call retain if it want to keep a reference on it.
- (NSString*) name {
return name;
}
// caller
NSString* name = object.name;
[name retain]; // if necessary. If the string is used only in the context of a method you do not have to retain it.
If you are using the returned value as a field in another class you should define your field like this:
#property(retain, nonatomic) NSString* name;
With this a retain will be called when you assign to the variable.
No, this is fine. autorelease will cause the value to be released when the current autorelease pool is drained.
Every retain must be matched with exactly 1 of either release or autorelease.
However, I believe both the retain and autorelease are unneeded here. Generally you want to use that autorelease idiom because you've alloc'ed something in the method.
No. The autorelease will balance it out. I don't think, however, that the retain and autorelease would be necessary. You can simply use return name.
As others have said, you do not need to retain or autorelease the property. Since callers of the 'getter' method did not create the object, they do not own it, and you are safe to assume that they won't tinker around with its retain count.
But, callers could potentially change the value of the variable returned by the getter, which would affect the object. Therefore, it would probably be a better idea to return a copy of your variable, especially since it is an NSString. (Getters for NSString objects often return a copy.)
- (NSString *)name {
return [[name copy] autorelease];
}
In this scenario, you are creating a copy of the variable, so you 'own' it. By autoreleasing it before it is returned, you ensure that it will survive long enough to be used in the caller's scope, and that any changes they make to the 'name' variable will not affect the underlying object.
I am just curious, do I need to add a further [name release] elsewhere to match up with the retain here in the getter?
- (NSString *)name {
return [[name retain] autorelease];
}
No, because you are already releasing it. autorelease just means “send yourself release later”.
I think you should review the memory-management rules.
I think I might have figured it out:
if [myString] is created outside the method then your safe to use ...
return myString;
if on the other hand [myString] is created inside the method and therefore needs to be released and returned, then you use.
myString = [[NSString alloc] initWithFormat: #"Send me home"];
return [myString autorelease];
This way the method sets [myString] to autorelease, Basically the object is created, set to autorelease and returned. The object will ultimately be released when the pool is destroyed.