I'm doing my first steps in finding memory leaks in xCode 4.5 and using the Leaks instrument. I found a couple of issues and seemed to fix them, but this one eludes me.
Here is the code:
RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = nm;
[imgInfo->name retain]; // I'm using it outside of this method
Leaks reports a leak in the second line, with the percentage next to the "i" at %100.
So I tried two things:
One, I marked nm with autohrleas like this:
NSString *nm = [[NSString stringWithUTF8String:img->name.c_str()] autorelease];
Two, I also tried calling release on nm after it's assignment to imgInfo->name so the code looks like this:
imgInfo->name = nm;
[imgInfo->name retain];
[nm release];
But in both cases the app crashes with BAD_ACCESS when I run it, and call [imgInfo->name UTF8String].
What am I missing?
EDIT following Rob's answer:
This is the RUBEImageInfo class:
#import "cocos2d.h"
#interface RUBEImageInfo : NSObject {
#public CCSprite* sprite; // the image
#public NSString* name; // the file the image was loaded from
#public class b2Body* body; // the body this image is attached to (can be NULL)
#public float scale; // a scale of 1 means the image is 1 physics unit high
#public float angle; // 'local angle' - relative to the angle of the body
#public CGPoint center; // 'local center' - relative to the position of the body
#public float opacity; // 0 - 1
#public bool flip; // horizontal flip
#public int colorTint[4]; // 0 - 255 RGBA values
}
#end
And the .m:
#import "RUBEImageInfo.h"
#implementation RUBEImageInfo
// Nothing much to see here. Just make sure the body starts as NULL.
-(id)init
{
if( (self=[super init])) {
body = NULL;
}
return self;
}
-(void) dealloc {
[name release];
[super dealloc];
}
#end
A couple of reactions:
Instruments identified where the leaked object was allocated, but in this case, this code might not be the source of the leak. You should:
ensure you release the name in the dealloc method of RUBEImageInfo; and
also, if you're setting name a second time, make sure you release the previous name object before you set it to a new object.
Your life will be much easier if you use declared properties rather than dereferencing class instance variables. For example, if name was declared as:
#property (nonatomic, copy) NSString *name; // you could use `retain`, too, but `copy` is safer when dealing with strings
Then you would set the name property as so:
RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo.name = nm;
// this is no longer needed as the `name` setter will take care of memory semantics
// [imgInfo->name retain]; // I'm using it outside of this method
By using the setter accessor method (i.e. the "dot syntax" of imgInfo.name), it will take care of a lot of routine memory semantics of releasing any previous object that name may have referenced, and it will do the necessary copy or retain. Obviously, the RUBEImageInfo method dealloc still needs to release name, but at least it simplifies the memory semantics of the name property of RUBEImageInfo objects.
Since you are using manual reference counting, I'd encourage you to investigate the "static analyzer" (invoked by selecting "Analyze" from Xcode's "Product" menu). The Leaks tool in Instruments will tell you what leaked, but it doesn't tell you where the leak happened; it has no way of knowing; it can only show you where the leaked object was allocated and you'll have to hunt down the logic error yourself. The static analyzer can sometimes point out errors that lead to leaks, but more importantly, show you where the leak was caused, rather than just where the leaked object was originally instantiated. You should have a clean bill of health from the static analyzer before you even bother running Instruments.
Looking at your code sample, if you're not going to use declared properties (not sure why you wouldn't, as it makes life easier, but to each his own), I'd suggest making sure you initialize all of your objects in init and release all of them in dealloc:
#implementation RUBEImageInfo
-(id)init
{
if ((self=[super init])) {
body = NULL;
name = nil;
sprite = nil;
// I might initialize other class instance variables here, too, but that's up to you
}
return self;
}
-(void) dealloc {
[name release];
// shouldn't you release `body` and `sprite`, too?
[super dealloc];
}
#end
Then your code that sets the name instance variable would make sure to release the previous object before setting the new object. Thus the initial instantiation might look like:
RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = [nm retain]; // retain the new object
But if you update it later, you should:
NSString *nm = [NSString stringWithUTF8String:someNewImg->name.c_str()];
[imageInfo->name release]; // release the old one
imgInfo->name = [nm retain]; // retain the new object
Related
I turned ARC off.
I have a property in a class declared like this:
#property(copy) NSString* name
I set name with a constant string:
[greeter setName:#"Jane"];
I implemented dealloc for my class like this:
-(void)dealloc{
[super dealloc];
}
I expected there would be a memory leak because I didn't release name. I'm using Xcode 6.2 and Product>Analyze does not identify any leaks, and neither does Instruments: Product>Profile, choose Leaks, hit the red Record button.
Here is the relevant code:
//
// Greeter.h
// Flashlight2
//
#import <Foundation/Foundation.h>
#interface Greeter : NSObject
#property(copy) NSString* name;
-(NSString*)description;
-(void)dealloc;
#end
....
//
// Greeter.m
// Flashlight2
//
#import "Greeter.h"
#implementation Greeter
-(NSString*)description {
NSString* msg = [[NSString alloc] initWithString:#"I am a Greeter"];
return [msg autorelease];
}
-(void)dealloc{
[super dealloc];
}
#end
...
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
Greeter* greeter = [[Greeter alloc] init];
[greeter setName:#"Jane"]; //constant string in memory for life of program
NSLog(#"%#", greeter);
[greeter release];
return YES;
}
After thinking about it for awhile, the only explanation that I can come up with is that the name setter doesn't actually copy the constant string. It seems like Obj-C does a type check on the string being assigned to the property, and because it's a constant string, Obj-C just assigns(?) the-pointer-to-the-constant-string to the name-pointer. Is something like that going on?
There's two optimizations at work here that combine to cause this result.
First: NSString literals are stored in a special segment of the binary, rather than allocated at runtime. They ignore retain and release, and are never allocated or deallocated.
Second: Copying an immutable NSString (including a string literal) instead just retains it, because the copy would be guaranteed to always be identical to the original. (This is accomplished by overriding the -copyWithZone: method in the private NSString subclass)
So in your scenario, the copy turns into a retain, the retain is ignored, and the deallocation wouldn't happen even if you did properly release the string in dealloc.
Is it a better practice, in a setter, to retain and release NSString as follows :
-(void) setName:(NSString *)newName
{
if(newName != nil)
{
[newName retain]:
[m_Name release];
m_Name = newName; //Where m_Name is a NSString *
}
//I'm not sure for this code, I have difficulties understanding memory-management in ObjC
}
Or to change the value via a NSMutableString :
-(void) setName:(NSString *)newName
{
if(newName != nil)
[m_Name setString:newName]; //Where m_Name is a NSMutableString *
}
If any or both of the methods are incorrect(s), let me know.
A couple of thoughts:
Best practice is to not write setters at all, to take advantage of the automatically synthesized accessor methods). Writing your own is only an opportunity to mess up your memory management or introduce a bug. You should have a compelling need for a custom setter before you write one.
The emerging convention for instance variable names is to use the property name preceded by a leading underscore (e.g., for a property called name, the ivar is _name). If you omit the #synthesize statement, the compiler included with recent versions of Xcode will do this automatically for you.
The question of what the setter should be makes no sense in the absence of your stating what memory qualifiers your property had. I'm going to assume you defined your property as retain.
Changing the property to a NSMutableString changes the behavior of your property and I would not advise that unless you really needed a mutable string for some reason.
Your first example does nothing if someone sets the name property to nil. But if someone wants to set it to nil, you should still (a) release the old name value; and (b) set your ivar to nil. (By the way, my code below takes advantage of the fact that sending a message to a nil object does nothing, so I don't need to check if it's nil or not, in this case.)
So, I assuming you have a property defined as follows:
#property (nonatomic, retain) NSString *name;
and a synthesize line that is either omitted or looks like:
#synthesize name = _name;
Then, I think the setter would look like:
-(void) setName:(NSString *)name
{
// if you want to program defensively, you might want the following assert statement:
//
// NSAssert(name == nil || [name isKindOfClass:[NSString class]], #"%s: name is not string", __FUNCTION__);
if (name != _name)
{
[_name release];
_name = name;
[_name retain];
}
}
By the way, I assume your init method properly initializes _name and that dealloc releases it.
- (id)init
{
self = [super init];
if (self) {
_name = nil;
}
return self;
}
- (void)dealloc
{
[_name release];
[super dealloc];
}
As bblum points out, it's prudent to use copy for your NSString properties:
#property (nonatomic, copy) NSString *name;
Then, I think the setter would look like:
-(void) setName:(NSString *)name
{
// if you want to program defensively, you might want the following assert statement:
//
// NSAssert(name == nil || [name isKindOfClass:[NSString class]], #"%s: name is not string", __FUNCTION__);
if (name != _name)
{
[_name release];
_name = [name copy];
}
}
But really, you simply shouldn't be writing setters unless you absolutely need to.
Finally, your code has a comment about finding memory management confusing. While you definitely need to understand it, I'd make two final suggestions:
Consider using Automatic Reference Counting (ARC). While this doesn't obviate the need to understand how memory management works (see the Advanced Memory Management Programming Guide), it does make it easier to write code that handles memory management properly. If you write manual reference counting (MRC) code, it's very easy to make simple memory management mistakes that ARC would otherwise take care of for you.
Especially if you're going to use MRC, avail yourself of Xcode's static analyzer ("Analyze" on the "Product" menu or press shift+command+B). This can facilitate finding many routine memory management issues that plague MRC code. The Finding Memory Leaks section of the Instruments User Guide also illustrates how to find leaks while debugging your code, but often the static analyzer can identify issues just by examining your code.
The first solution is better. This is how retain properties are handled. You retain the new value and then release the old value. Also if the nil case is not crucial to be handled, you can depend on the default implementation, generated by #synthesize.
For the second solution, it's really unnecessary, and it's a little bit against convention. Also, in this solution, you have to initialize m_name before ever assigning any string to it. You can do that in init.
- (void) init {
if (self = [super init]) {
m_name = [[NSMutableString alloc] init];
}
}
Conclusion: First solution is definitely better.
When you synthesize a property (see below)
#interface CelestialBody : NSObject {
NSString *name;
}
...
#interface Planet : NSObject {
NSString *name;
int mass;
CelestialBody *moon;
}
#property(nonatomic, retain) NSString *name;
#property(assign) int *mass;
#property(nonatomic, retain) CelestialBody *moon;
...
#implementation Planet
#synthesize name;
#synthesize mass;
#synthesize moon;
...
You get setters and getters for each of the iVars (i.e.)
[newPlanet setName:#"Jupiter"];
[newPlanet setMass:57];
NSString *closestName = [newPlanet name];
int largestMass = [newPlanet mass];
CelestialBody *newMoon = [[CelestialBody alloc] initWithName:#"Callisto"];
[self setMoon:newMoon];
[newMoon release];
but you also get the ability to release the object using ...
// Releases the object (frees memory) and sets the object pointer to nil.
[self setMoon: nil];
There will of course be deallocs for each Class.
// Moon
-(void)dealloc {
[name release];
[super dealloc];
}
// Planet
-(void)dealloc {
[name release];
[moon release];
[super dealloc];
}
Am I getting this right?
gary
Unless your planet object is declared as a property within some other class, using the retain/copy attributes, you can't release it this way.
When you declare a property using retain/copy, the resulting setter will release the old value and assign the new value, retaining or copying it in the process. If you pass nil, you will release the old value and assign nil, retaining or copying it, and retaining/copying nil is nil, so effectively you end up releasing the old value and assigning nil to the ivar.
This is an acceptable way to release instance variables.
In order to be able to release your newPlanet instance this way, you'd have to have declared it in a class as a property with either retain or copy.
As a further example, since your planet object declares its properties in this way, you could release those using this method.
Or in the Planet class's dealloc method, you could do:
self.name = nil;
This would release name and assign nil to it.
"you also get the ability to release the object"
Yes, as long as you didn't declare it with the assign attribute.
As you probably know, one of the reasons (although perhaps not the primary one) for using declared properties is that you can do:
self.moon = aMoon;
rather than;
[self setMoon:aMoon];
They are equivalent. That means that your deallocation can look like this:
self.moon = nil; // Releases and sets to nil
But remember to never just do:
moon = nil; // Sets to nil, doesn't release
It's very good practice to not only release the object, but to set the variable to nil, as you do, because otherwise some other code could mistakenly try to use the pointer that is left in the variable.
Your example shows the synthesis of one class's ivars (those of Planet) but the use of another (whatever "self" is). Is the "newPlanet" property of "self" in your last example also synthesized as (retain)? If so, then: Yes, setting newPlanet to nil will release whatever self's old "newPlanet" was.
I think you are not getting it right.
After your question update, yes, you can do that, and also:
self.moon = [[CelestialBody alloc] initWithName:#"Callisto"];
and release it later, probably in your dealloc method:
self.moon = nil;
Apple Objective-c 2.0 Properties and Memory Management docs are pretty good. Check Mac Dev Center library.
This is just a test to help me learn Objective-C, it uses NSMutableArray to add tire objects to an instance variable in a car object:
// INTERFACE
#interface CarBody : NSObject {
NSMutableArray *tires;
}
// Should this be (id *) it works but I was convinced it would be pointer?
- (void) addTire:(id)newTire;
#end
#interface TireSnow : NSObject {
}
#end
// IMPLEMENTATION
#implementation CarBody
- (void) addTire:(id)newTire {
[tires addObject:newTire];
// ** Release here or in main()?
}
- (id) init {
[super init];
tires = [[NSMutableArray alloc] init];
NSLog(#"_init: %#", NSStringFromClass([self class]));
return self;
}
- (void) dealloc {
NSLog(#"_deal: %#", NSStringFromClass([self class]));
[tires release];
[super dealloc];
}
#end
I do have a few questions ...
In the addTire method, is the (id) right, I thought it was going to be (id *)
Releasing the item I am adding to the array, should I do it inside the setter or in main() after I call it?
Am I allocating / releasing the NSMutableArray (tires) in the right place, it feels right?
Is there a way to do this with NSArray (as I only want 4 tires), I did try this but got mixed up trying to alloc the array and define its size.
thanks in advance for any help ...
gary
EDIT:
I am reading the memory management rules, but they do take some time to absorb and do require a certain level of understanding that is difficult to gain when starting out. What I am wondering about in this situation is where would I release the newSnowTire that I alloc in main. When I add it to the array in the setter does that create a new object in the array (thats my understanding) so my thinking was that I would need to release the instance I got from alloc?
// MAIN
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
CarBody *newCarBody_001;
TireSnow *newSnowTire_001;
newCarBody_001 = [[CarBody alloc] init];
newSnowTire_001 = [[TireSnow alloc] init];
[newCarBody_001 addTire:newSnowTire_001];
// Clean up
[newCarBody_001 release];
[newSnowTire_001 release];
[pool drain];
return 0;
}
EDIT_002:
Just added the code to generate all 4 tires with the tire release moved into the loop after the setter is called.
// CREATE TIRES
for(int loopCounter=0; loopCounter<4; loopCounter++) {
newSnowTire_001 = [[TireSnow alloc] init];
[newCarBody_001 addTire:newSnowTire_001];
[newSnowTire_001 release];
}
I just checked this and it is correct ...
NewSnowTire_001 (alloc) RetainCount = 1
NewSnowTire_001 (addTire) RetainCount = 2
NewSnowTire_001 (release) RetainCount = 1
NewSnowTire_001 Finally Released by dealloc method.
(id) or (TireSnow*) is similar, I had problems with understanding this in the beginning too. So basically an object is of a pointer type (kind of), but the id is already a pointer, so you don't need a * after it.
In main. Releasing should happen in the same place as the alloc/retain/copy.
Seems okay to me.
You can use [[NSMutableArray alloc] initWithCapacity:4]. This is only a hint to the array, it will automatically expand if you insert more items. Check [tires length] in the addTire method.
Your -init should look more like this:
-(id)init
{
if (self = [super init]) {
// init here
}
return self;
}
This allows self to be nil if something breaks in the init-chain.
You should use id (not id*). Objective-C do not have a concept of a root object as you have in for example Java, where java.lang.Object is the root class for any and all classes. Cocoa adds two root classes (classes without a super class) named NSObject, and less common NSProxy. id is a pointer to any object regardless of super class.
It is unfortunate that id, and also Class, are defined as a pointers, which means they are the only places where you should not add the '*' character when defining references. An unfortunate legacy from the old days.
Release in main, you should always release objects int he same scope that you create or retain them. The addTire: method is exceptionally god example of this, never release objects that has been handed to you as an argument. Only release objects handed to you as a result (And even then only from the alloc, new and copy method).
The allocation and release of the instance variable tires is a schoolbook example of where it should be done. I would expand the init to check for the super class result, as this though (Never trust super to always work, or even return the same instance):
- (id) init {
self = [super init];
if (self) {
tires = [[NSMutableArray alloc] init];
NSLog(#"_init: %#", NSStringFromClass([self class]));
}
return self;
}
You can use NSArray if you have access to all four tires from the start. Best way would probably be to require the tires in the init method. If that is not a possibility then you have nothing to gain from using an NSArray over a NSMutableArray.
The type id is defined like this (in objc.h):
typedef struct objc_object {
Class isa;
} *id;
So id is already a pointer to an object. An id* would be a pointer to a pointer.
As for where you should release the tire — there's nothing in the code you posted that shows a need to release it at all. That object never claims ownership of the tire, so it has no need to release it. If something claimed ownership of the tire somewhere else in your code, then that object has a responsibility to release its claim when it's finished.
This is explained in the Objective-C memory management rules. It's pretty short and a must-read.
Can anyone tell me if the NSString instance variable "planetName" needs to be allocated / released by me (as in the example below) or is that done when the class instance is created / allocated?
My understanding is that int and float don't need to be, but not sure about NSString & NSArray ...
#interface PlanetClass : NSObject {
NSString *planetName;
}
- (NSString *)planetName;
- (void)setPlanetName:(NSString *)value;
#end
Like this ...
- (id) init {
[super init];
planetName = [[NSString alloc] init];
return self;
}
- (void) dealloc {
[planetName release];
[super dealloc];
}
** ---------------------------------- **
EDIT: EDIT: Here is another version
** ---------------------------------- **
int main(int argc, const char *argv[]) {
// ** Allocated here
PlanetClass *newPlanet_01 = [[PlanetClass alloc] init];
NSString *newPlanetName = [NSString alloc] init];
// ** Set the instance variable pointer here
newPlanetName = #"Jupiter";
[newPlanet_01 setPlanetName:newPlanetName];
// ** Released here
[newPlanet_01 release];
return 0;
}
the init & dealloc methods would then be like this ...
- (id) init {
[super init];
return self;
}
- (void) dealloc {
// Always release the current copy of planetName
// pointed to by the class instance.
[planetName release]
[super dealloc];
}
The setPlanetName method would look like this ...
- (void)setPlanetName:(NSString *)newPlanetName {
if (planetName != newPlanetName) {
[planetName release];
planetName = [newPlanetName copy];
}
}
PS: I am not using properties or synthesize, I have not gotten that far yet.
cheers -gary-
Your code is valid, but there's probably no reason to initialize planetName to an empty string. One of the nice features of Objective-C is that you can send messages to a nil object with no consequence. If your class is initialized and you never call -setPlanetName:, planetName will be nil (instance variables are always initialized to nil), so when your -dealloc method calls [planetName release], nothing will happen.
In general, the best practice is to use -copy when setting an NSString instance variable, and -retain when setting most other objects as instance variables. As such, your -setPlanetName: method would look something like this:
- (void)setPlanetName:(NSString *)newPlanetName {
NSString *tempPlanetName = [newPlanetName copy];
[planetName release];
planetName = tempPlanetName;
}
You still have an issue with your new code.
In your main function, you release newPlanetName but this is a little wrong. Your PlanetClass retained it with its setPlanetName: method, but your PlanetClass never releases it again unless the name of the planet changes. It should not be up to the caller of setPlanetName: to keep hold of the string, it is your classes responsibility to deal with it appropriately.
Your old dealloc method is correct. It should release the planet's name because your PlanetClass no longer needs it. Your main method should not release the planet's name because the string returned by stringWithString: does not belong to you, and you give it to PlanetClass to take care of.
So, keep your old dealloc method, and remove the [newPlanetName release] from the main function and you should be alright from there.
As a shortcut, you can even call [newPlanet_01 setPlanetName:#"Jupiter"] and do away with the newPlanetName variable altogether in your main function.
planetName is a pointer which, like an int or float, does not need to be allocated or initialized.
Just like you can assign values to an int or float, you can point planetName at different instances of a string, or it can point at nothing.
When you init your class, planetName will be nil (not pointing at anything). If you point planetName to an instance of a string, you have to retain that string, and release in dealloc.
In other words, this:
planetName = [[NSString alloc] init];
is unnecessary and meaningless.
In your setPlanetName method you would need to release the existing string that planetName is pointing to, assign planetName to the new string, and then retain the new string.
Your dealloc method is correct.
Your code looks good. NSObject subclasses (NSString included) need to have their memory mananged by the object that owns them. In this case, that owner is PlanetClass.