Memory Leak in initWithFrame - iphone

i use a UIView subclass with an NSMutableArray of other Views to indicate values as bars.
I init it in my initWithFrame. The Instruments tells after a few create and remove of my UIView subclass that there is a leak on the alloc of the NSMutableArray.
Thats why i framed it with the if to avoid multiple objects. But doesn't help
- (id) initWithFrame :(CGRect)frame
{
self = [super initWithFrame:frame];
if (self.uiValueSubviews == nil){
self.uiValueSubviews = [[NSMutableArray alloc]init];
}
return self;
}
- (void)dealloc {
[self.uiValueSubviews release];
[super dealloc];
}
Am i doing something wrong with the dealloc?
Thanks for your Help

Two problems I see with memory management involving your property.
Properties should always be set to
an autoreleased object or an
object you will be releasing on your
own.
Never send release directly to a property. I prefer to release underlying variable if possible (ex. [_uiValueSubviews release];)
Change the code to the following.
- (id) initWithFrame :(CGRect)frame
{
self = [super initWithFrame:frame];
if (self.uiValueSubviews == nil){
//Set to autoreleased array
self.uiValueSubviews = [NSMutableArray array];
}
return self;
}
- (void)dealloc {
//nil the value
self.uiValueSubviews = nil;
[super dealloc];
}

You should do like this :
- (id) initWithFrame :(CGRect)frame
{
if ((self = [super initWithFrame:frame]))
{
if (self.uiValueSubviews == nil){
uiValueSubviews = [[NSMutableArray alloc]init];
}
return self;
}
- (void)dealloc
{
self.uiValueSubviews = nil;
[super dealloc];
}
You uiValueSubviews is probably a retain property so when you alloc, your retainCount is +1 and self. +1 too.

An other way, avoiding autoreleased objects, would be:
// ...
if (self.uiValueSubviews == nil)
{
NSMutableArray *uiValueSubviews_tmp = [[NSMutableArray alloc] init];
// maybe do something with uiValueSubviews_tmp
self.uiValueSubviews = uiValueSubviews_tmp;
[uiValueSubviews_tmp release];
}
// ....
As far as I know, that's how Apple does it in their examples.

Related

How to release memory for declared object in iPhone [duplicate]

This question already has answers here:
app crash in the dealloc
(2 answers)
Closed 9 years ago.
I'm facing small problem,
I declare an array in .h file and allocate it in viewDodLoad method. In dealloc method I check if array not equal to nil then array=nil. But it's crashing in iOS 5.1.1. I can't understand reason for this crash.
My code,
#interface SampleApp : UIViewController
{
NSMutableArray *objArray;
}
#end
#implementation SampleApp
- (void)viewDidLoad
{
[super viewDidLoad];
objArray=[[NSMutableArray alloc]init];
}
-(void)dealloc
{
[super dealloc];
if (objArray!=nil)
{
[objArray removeAllObjects];
[objArray release];objArray=nil;
}
}
Add [super dealloc]; at the end of dealloc method and not at beginning. It is recommended by Apple in its documentation for dealloc method.
When not using ARC, your implementation of dealloc must invoke the superclass’s implementation as its last instruction.
Modify your code as below,
-(void)dealloc
{
if (objArray!=nil)
{
[objArray removeAllObjects];
[objArray release];objArray=nil;
}
[super dealloc];
}
Also, you need not call [objArray removeAllObjects] when you are releasing the entire array. When array is released, internally it will call release on all contained objects.
Hope that helps!
[super dealloc] method must be call in end of this method. Because you can not access variables of the superclass anymore because they are released when you call [super dealloc]. It is always safe to call the superclass in the last line.
-(void)dealloc
{
// ----------- your stuff ------------
[super dealloc];
}
With manual memory management, your -dealloc method looks as follows:
-(void)dealloc
{
[objArray release]; // objArray *may* be nil, and this is
// sufficient to release all elements as well.
// call super at the end
[super dealloc];
}
Additionally, you have a potential memory leak in your method -viewDidLoad. If you do it like your example:
- (void)viewDidLoad
{
[super viewDidLoad];
objArray=[[NSMutableArray alloc]init];
}
you may assign objArray a new pointer even if objArray already holds a valid object. The new pointer value will simply override the old, and thus you cannot release the old anymore.
One way is to check whether objArray is not nil and then release it before assigning it a new value:
- (void)viewDidLoad
{
[super viewDidLoad];
if (objArray) {
[objArray release], objArray = nil;
}
objArray = [[NSMutableArray alloc]init];
}
The better approach however is to employ "lazy initializing properties":
First, define an "internal property" for your array (unless you want the array publicly accessible). In your .m file:
// In your implementation file define a private property in a class extension:
#interface SampleApp ()
#property (nonatomic) NSMutableArray* objArray;
#end
#implementation SampleApp
#synthesize objArray = _objArray; // this will create the setter
-(void)dealloc
{
[_objArray release];
[super dealloc];
}
// Lazy init property: (this is the getter)
- (NSMutableArray*) objArray {
if (_objArray == nil) {
_objArray = [[NSMutableArray alloc] init];
}
return _objArray;
}
- (void) viewDidLoad {
[super viewDidLoad];
// When needing the array, simply *and always* access it
// through the property "self.objArray":
NSUInteger count = [self.objArray count];
}
...
Lazy initialization of properties are quite handy. Basically, you won't worry anymore if they are initialized or not - they simply are, when you use the property accessor.

using custom init method in iphone -identifying a leak

For one of my custom classes, I have defined a method called initialize to set some instance variables at the same time as the init. The code is below. The analyzer tool is reporting a leak in viewDidLoad on the line with [[Employee alloc]..
Since I am releasing the variable in the dealloc, I thought that this should be fine..what could be the issue? thanks in advance.
#interface testViewController : UIViewController <UITextFieldDelegate>{
Employee *employee;
}
- (void)viewDidLoad {
if(employee ==nil)
employee = [[Employee alloc] initialize:#"John"];
if (![employee.entityName isEqualToString:#"Test"]) { //The leak is reported here for object allocated above
///...
}
}
- (void)viewDidUnload {
[super viewDidUnload];
employee = nil;
}
- (void)dealloc {
[super dealloc];
[employee release];
}
//In the Employee class
-(id) initialize:(NSString*) name{
self = [super init];
self.entityName = name;
return self;
}
In your viewDidUnLoad you need to release employee before it gets set to nil. Else in your dealloc, you are just releasing nil.
ie
- (void)viewDidUnload {
[super viewDidUnload];
[employee release];
employee = nil;
}

NSIndexPath: message sent to deallocated instance

Any help you can offer would be appreciated.
I have a app that has a tableView, detailView, flipView, and moreDetail View. It is fine moving through the transitions until the 26th element. The app crashes when I hit buttons that navigate to the flip and moreDetailView.
I am given the error Msg: [NSIndexPath row] message sent to deallocated instance.
I think I may be calling the indexPath too many times, but why does everything work well up until the 25th element and then stop working? How did the NSIndexPath get deallocated? I never deallocated it.
If you know, please help. Thank you!!!
Xcode says the problem is here:
#implementation produceView aka *detailView*
- (IBAction)showInfo {
FlippedProduceView *fView = [[FlippedProduceView alloc]initWithIndexPath:index];
fView.flipDelegate = self;
fView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:fView animated:YES];
[fView release];
}
- (IBAction) buttonPushed:(id)sender
{
picView *pictureView = [[picView alloc]initWithIndexPath:index];
pictureView.picDelegate = self;
pictureView.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:pictureView animated:YES];
[pictureView release];
}
-(id)initWithIndexPath:(NSIndexPath *)myIndexPath {
if (self == [super init]) {
path = myIndexPath;
}
return self;
}
#implementation picView aka *moreDetailView*
- (void)viewDidLoad {
RipeGuideAppDelegate *AppDelegate = (RipeGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
self.picViewArray = AppDelegate.arrayProduceInfo;
NSMutableDictionary *dictionary = [picViewArray objectAtIndex:path.row];
}
#implementation FlippedProduceView aka *flipView*
- (id)initWithIndexPath:(NSIndexPath *)myIndexPath {
if (self == [super init]) {
indexes = myIndexPath;
}
return self;
}
- (void)viewDidLoad {
RipeGuideAppDelegate *AppDelegate = (RipeGuideAppDelegate *)[[UIApplication sharedApplication] delegate];
self.flipViewArray = AppDelegate.arrayProduceInfo;
NSMutableDictionary *dictionary = [flipViewArray objectAtIndex:indexes.row];
}
You should use properties (#property (retain) NSIndexPath *path;) instead of instance variables, so then when you do self.path = myIndexPath then it raises the retain count so it won't be deallocated when IndexPath is autoreleased.

Constructor in Objective-C

I have created my iPhone apps but I have a problem.
I have a classViewController where I have implemented my program.
I must alloc 3 NSMutableArray but I don't want do it in grapich methods.
There isn't a constructor like Java for my class?
// I want put it in a method like constructor java
arrayPosition = [[NSMutableArray alloc] init];
currentPositionName = [NSString stringWithFormat:#"noPosition"];
Yes, there is an initializer. It's called -init, and it goes a little something like this:
- (id) init {
self = [super init];
if (self != nil) {
// initializations go here.
}
return self;
}
Edit: Don't forget -dealloc, tho'.
- (void)dealloc {
// release owned objects here
[super dealloc]; // pretty important.
}
As a side note, using native language in code is generally a bad move, you usually want to stick to English, particularly when asking for help online and the like.
/****************************************************************/
- (id) init
{
self = [super init];
if (self) {
// All initializations you need
}
return self;
}
/******************** Another Constructor ********************************************/
- (id) initWithName: (NSString*) Name
{
self = [super init];
if (self) {
// All initializations, for example:
_Name = Name;
}
return self;
}
/*************************** Another Constructor *************************************/
- (id) initWithName:(NSString*) Name AndAge: (int) Age
{
self = [super init];
if (self) {
// All initializations, for example:
_Name = Name;
_Age = Age;
}
return self;
}

Return to RootController is crashing my app

My application is crashing, I think, in RootController.m and I don't know why. It occurs when I am in any view controller and I push the back button. It briefly returns to RootController and then it crashes. There is no messages on the console. I don't think it is the ViewController as I have tried more than one.
Here is the code.
#import "confirmViewController.h"
#implementation confirmViewController
#synthesize lblStatus;
#synthesize lblCardType;
#synthesize lblCardNumber;
#synthesize lblExpires;
#synthesize lblAmount;
#synthesize lblApproval;
#synthesize strConfirmation;
#synthesize strCardNumber;
#synthesize strExpires;
#synthesize strAmount;
#synthesize strApproval;
/*
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
//prepare confirmation, all that is needed is the first string
NSArray *strings = [strConfirmation componentsSeparatedByString: #","];
NSString *strPreParsed = [strings objectAtIndex:0];
//break out yes/no so we can set status
//NSString *strYesNO = [strPreParsed substringToIndex:2];
NSString *strYesOrNo = [strPreParsed substringWithRange: NSMakeRange(1, 1)];
//save approval for later
strApproval = strYesOrNo;
//debug
NSLog(#"strNo= %#",strYesOrNo);
NSLog(#"strPreParsed= %#", strPreParsed);
if([strYesOrNo compare:#"Y"] == NSOrderedSame)
{
lblStatus.text = #"Approved";
lblStatus.textColor = [UIColor greenColor];
}
if([strYesOrNo compare:#"N"] == NSOrderedSame)
{
lblStatus.text = #"Declined";
lblStatus.textColor = [UIColor redColor];
}
if([strYesOrNo compare:#"U"] == NSOrderedSame)
{
lblStatus.text = #"Try Again";
lblStatus.textColor = [UIColor redColor];
}
//set card type
if([lblCardNumber.text compare:#"4"] == NSOrderedSame)
{
lblCardType.text = #"Visa";
}
if([lblCardNumber.text compare:#"5"] == NSOrderedSame)
{
lblCardType.text = #"Master";
}
if([lblCardNumber.text compare:#"6"] == NSOrderedSame)
{
lblCardType.text = #"Discover";
}
//set cardnumber
lblCardNumber.text = strCardNumber;
//set expires
lblExpires.text = strExpires;
//set amount
lblAmount.text = strAmount;
//set approval string
lblApproval.text = strPreParsed;
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (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.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
//show signature
sigCaptureViewController *yetAnotherViewController = [[sigCaptureViewController alloc] initWithNibName:#"sigCaptureView" bundle:nil];
[self.navigationController pushViewController:yetAnotherViewController animated:YES];
[yetAnotherViewController release];
}
- (void)dealloc {
[super dealloc];
[lblCardType dealloc];
[lblCardNumber dealloc];
[lblExpires dealloc];
[lblAmount dealloc];
[lblApproval dealloc];
[lblStatus dealloc];
[strConfirmation dealloc];
[strCardNumber dealloc];
[strExpires dealloc];
[strAmount dealloc];
[strApproval dealloc];
}
#end
You are most likely releasing something twice in your SalesViewController, it's crashing when that object's dealloc is getting called and doing the 2nd release.
You didn't include that contorller's code, either look for it yourself or paste it here and I'll help you spot it :)
Here's a scenario you should look for:
// somewhere within your sales controller
- (void)someWhere {
NSArray *arr = [NSArray array];
self.myArray = arr;
[arr release]; // notice how arr wasn't initialized with an init
// so no release is required
// but since your myArray is a #property(retain) it won't crash here
// because the property did a retain
}
- (void)dealloc {
[myArray relase]; // this does the 2nd release and BOOM
}
EDIT after your target view controller was pasted:
It might be because you forgot to set one of the properties you're releasing in the dealloc. Try setting a breakpoints in your dealloc and see if one of the properties is actually null before releasing it, if so, that's why it crashes.
EDIT #2, are you sure you want to be calling [lblSometing dealloc] instead of [lblSomething release]?