I'm using leaks tool of instruments. It says that I have some leaks in the init method. It shows that NSMutableArray has leak.
I don't see any leaks.
#interface BookSettings : NSObject
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSMutableArray *authors;
#end
- (id)init
{
self = [super init];
if(self)
{
title = [[NSString stringWithString:#""] retain];
authors = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc
{
[title release];
[authors release];
[super dealloc];
}
The provided code is OK, the problem is somewhere else where authors is retained without a balancing release. Leaks just points to the place ivar is created, not where the missing release should be. Check all the places where the retain count is increased.
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the problem code to run, stop recording, search for there ivar of interest, drill down and you will be able to see where all retains, releases and autoreleases occurred.
Seriously consider using ARC, there is little reason not to, ARC supports back to iOS 4.x.
BTW:
title = [[NSString stringWithString:#""] retain];
can be more compactly written:
title= #"";
I think it's from title.
You already have that property nonatomic, retain, so it this means a retain count of 1.
Then you specify another retain, making the retain count 2.
In the dealloc, you release it once, decreasing the retain count to 1. So this 1 reference that keeps retaining the string is the leak.
I don't understand why you are initialising the string like that anyway...
Related
Is my following code contains a memory leak?
please help me here!
NSMutableArray *arrInfo = [[NSMutableArray alloc] init];
appDelegate.arrAppInfo = arrInfo;
[arrInfo release];
What you did is perfectly valid in a non-ARC environment IF the property arrAppInfo is declared as a retain (or strong) property. In fact what ARC does in a similar situation is just putting a release when it detect that the arrInfo property is no longer used in the current scope.
To go deep:
NSMutableArray *arrInfo = [[NSMutableArray alloc] init]; //arrInfo retain count = 1
appDelegate.arrAppInfo = arrInfo; //arrInfo retain count = 2
[arrInfo release]; //arrInfo retain count = 1
If you weren't releasing the arrInfo variable after assigning it to a retained property you would have caused a memory leak in the future when reassigning or releasing the arrAppInfo property, since its retain count wouldn't be 0.
It depends on how arrAppInfo is defined in appDelegate.
If its a strong reference, this would be good as long as appDelegate releases arrAppInfo at some point.
#property (nonatomic, retain) NSMutableArray *arrAppInfo; //All good
If its a weak reference, then you will get an error when you try to access arrAppInfo because its been released.
#property (nonatomic, assign) NSMutableArray *arrAppInfo; //Trouble
I'm wondering if I am managing the memory of an Array correctly. Below I use this array with a tableView, so I want to keep it around for the life of the ViewController. Since I create it as a property I'm a little confused on the retain count and how to handle it since I'm alloc'ing it in the code. Below is how I currently have it coded.
in .h
#property (nonatomic, retain) NSMutableArray *mutableArray;
in .m
self.mutableArray = [NSMutableArray alloc] init];
//fill with object I'm going to be using throughout the life of the viewController
- (void) dealloc {
[mutableArray release];
[super dealloc];
}
Thank you!
You will leak your array if you're doing it that way. because your property is set to retain, self.mutableArray = [[NSMutableArray alloc] init]; is the same as mutableArray = [[[NSMutableArray alloc] init] retain];.
So change it to
self.mutableArray = [NSMutableArray array];
iOS will do memory management by itself. Here is Apple Arc Documentation. There is also an excellent condensed information about memory management from Mikeash Friday Q&A blog
Im very confused with the memory management.
Declared variable allNoticeArray in .h file:
#interface NoticeViewController : UITableViewController
{
NSMutableArray *allNoticeArray;
}
#property (nonatomic, retain) NSMutableArray *allNoticeArray;
#end
Alloc and init the variable in .m file:
#implementation NoticeViewController
#synthesize allNoticeArray;
- (void)viewDidLoad
{
[super viewDidLoad];
self.allNoticeArray = [[[NSMutableArray alloc] init] autorelease];
}
- (void)dealloc
{
[super dealloc];
/*
***should I release allNoticeArray here or not?***
*/
//[allNoticeArray release];
}
Should I release the allNoticeArray in dealloc function or not?
Thank you in advance!
It looks like you're manually managing your memory rather than using ARC.
If you're using IOS5 it might be easier for you to convert your project to ARC, then you won't have to worry about dealloc in this context.
If you don't want to use ARC you do need to release it in this context because you alloc'd it in viewDidLoad. You might also be interested in this article about dealloc.
Yes, you have to release the object. You could do the below in your dealloc method which will release your object.
self.allNoticeArray = nil;
REASON:
Although you have autoreleased the array you have declared your property as retain. So the object will be retained and used. So to totally remove the object from memory you should again call release over it.
You can learn everything about memory management here https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html
When not using ARC you should use the release in the dealloc. You are right in saying that your retain in the .h file increases the retain count by one. The Alloc/Init creates an object with a retain count of one. The auto release would counter that retain, however your dealloc release would count the retain in the .h.
Setting self.allNoticeArray=nil; is not the same as a release, but the link from sElan is a great link.
The rule of pre-ARC memory management is this: if you alloc, retain, or copy an object you must release it later or it will leak. Your property is set to retain, so whatever value it holds will be retained. You must balance it with a release in dealloc.
The short answer is NO, but you are doing a few things that are not recommended. In your code you are retaining your array twice in the single line. In the code below it is only retain once.
You should initialize the array like so -
NSMutableArray *array = [[NSMutableArray alloc] init] autorelease];
self.allNoticeArray = array;
I would recommend you look into using ARC, it makes memory management a non issue in IOS 5.
Either I don't understand the Instruments Leaks tool at all, or I am going mad. I have run the tool on my iphone app, and it shows a couple of leaks. If I understand it correctly, for one of the leaks, it says that it is an NSDate object allocated by my method "writeHeading". The method that allocates the object is: "dateWithTimeIntervalSinceReferenceDate:". However, my writeHeading method does not use that method. In fact, that method is not used anywhere in my whole application.
Does anybody have an idea what could be going on here?
Here is the code of writeHeading:
- (void) writeHeading:(CLHeading *)heading
{
if (self.inFlight) {
[log writeHeading:heading];
} else {
IGC_Event *event = [[IGC_Event alloc] init];
event.code = 'K';
event.timestamp = heading.timestamp;
event.heading = heading;
[self addEvent:event];
[event release];
}
}
Here is a screenshot of Instruments:
And here is the definition of IGC_Event (as asked by multiple responders):
#interface IGC_Event : NSObject {
int code;
CLLocation *location;
CLHeading *heading;
NSString *other;
NSDate *timestamp;
}
#property int code;
#property (nonatomic, retain) CLLocation *location;
#property (nonatomic, retain) CLHeading *heading;
#property (nonatomic, retain) NSString *other;
#property (nonatomic, retain) NSDate *timestamp;
#end
#implementation IGC_Event
#synthesize code;
#synthesize location;
#synthesize heading;
#synthesize other;
#synthesize timestamp;
#end
Assuming no ARC, you need to make sure IGC_Event objects release their timestamp and other references that may have been retained or copied.
So in IGC_Event you need a dealloc something like this:
- (void) dealloc {
[timestamp release];
[location release];
[heading release];
[other release];
[super dealloc];
}
Leaks is just telling you where that timestamp object was created, not where you should have released it.
That may not be the only place you are leaking of course, but that's 4 potential leaks right there.
When the compiler runs your code, there are the methods directly called by you (which in your screenshot have a little person next to them) and then the methods that are invoked in the core frameworks as a result. The method in question results from this piece of code:
event.timestamp = heading.timestamp;
You could manage this process yourself if you wanted to:
NSDate *eventTimestamp = heading.timestamp;
event.timestamp = eventTimestamp;
Incidentally, storing that timestamp is entirely redundant and uses unnecessary memory, since you also store the heading with all its properties in event.heading so at any time you can access that timestamp with event.heading.timestamp. However, you may have other reasons for storing it separately.
Do you have the implementation of the IGC_Event class? Is it possible that the setter for its timestamp property is calling dateWithTimeIntevalSinceReferenceDate:? (Not an unreasonable thing to do, so far as I can tell. That would ensure that its timestamp is of class NSDate itself, and not a subclass. It would also ensure that it's independent of the timestamp that was passed in.)
(Disclaimer: I'm really not much of an Objective-C-er. If this seems like a stupid question, then it probably is!)
We have a lot of staff that are relatively new to iOS programming and memory management in general. I want to build an app with a couple of labels showing retain counts and a some buttons to increment and decrement those retain counts.
Does anyone know of anything out there already that would work or have any advice on setting this up so it will get my point across? I have a working version, but it doesn't seem to be working the way I think it should.
ViewController.h
#import <UIKit/UIKit.h>
#interface MemoryTestingViewController : UIViewController {
UILabel *retainCount;
UILabel *descLabel;
UIButton *addRetain;
UIButton *addRelease;
UIButton *access;
NSMutableString *myString;
}
#property (nonatomic, retain) IBOutlet UILabel *retainCount;
#property (nonatomic, retain) IBOutlet UILabel *descLabel;
#property (nonatomic, retain) IBOutlet UIButton *addRetain;
#property (nonatomic, retain) IBOutlet UIButton *addRelease;
#property (nonatomic, retain) IBOutlet UIButton *access;
#property (nonatomic, retain) NSMutableString *myString;
-(IBAction)pressedRetain:(id)sender;
-(IBAction)pressedRelease:(id)sender;
-(IBAction)pressedAccess:(id)sender;
#end
ViewController.m
-(IBAction)pressedAccess:(id)sender {
descLabel.text = #"Accessing myString, did we crash";
myString = [NSMutableString stringWithFormat:#"Accessing myString"];
retainCount.text = [NSString stringWithFormat:#"%i", [myString retainCount]];
}
-(IBAction)pressedRetain:(id)sender {
descLabel.text = #"Adding 1 to retain count for myString";
[myString retain];
retainCount.text = [NSString stringWithFormat:#"%i", [myString retainCount]];
}
-(IBAction)pressedRelease:(id)sender {
descLabel.text = #"Adding 1 release to myString";
[myString release];
retainCount.text = [NSString stringWithFormat:#"%i", [myString retainCount]];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
// init our variable string
myString = [[NSString alloc] init];
descLabel.text = #"myString retain count after alloc/init";
// fill our label with myString's retain count starting out
retainCount.text = [NSString stringWithFormat:#"%i", [myString retainCount]];
[super viewDidLoad];
}
When this runs, it seems fine, but crashes whenever I try press the retain button. If anyone has any advice how to clean this up a bit, I would appreciate it. Ideally I would like them to press the access button when the retain count hits zero and have the app crash, but the access button should work as long as the retain count is 1 or better. Thanks.
The retainCount of an object is tricky business.
If you were to continue down this path, you should be aware of the following details:
retainCount can never return 0
messaging a dangling pointer is not guaranteed to crash
retain count cannot be known once you have passed an object through any system API due to implementation details
any subclass of any system class may have an unknown retain count due to implementation details
retain count never reflects whether or not an object is autoreleased
autoreleases is effectively thread specific while the retain count is thread global
some classes are implemented with singletons some of the time (NSString, certain values of NSNumber)
the implementation details change from platform to platform and release to release
attempting to swizzle retain/release/autorelease won't work as some classes don't actually use those methods to maintain the retain count (implementation detail, changes per platform/release, etc..)
If you are going to teach retain/release, you should be treating the retain count as a delta and focus entirely on "If you increase the RC, you must decrease it".
retainCount is notoriously unreliable and the values it returns can be very strange. Check this post out: