Memory Management Headache - iphone

I get leaks if I dont put it in dealloc. I get a crash EXC_BAD_ACCESS If I do. I cannot see anything wrong with this code. The bad access is pointed at [events release]. Have I made a mistake in the code below or is Instruments just having a laugh at my expense?
events is an NSArray
#interface EventsViewController : UITableViewController
{
#private
NSArray *events;
}
- (void)viewDidLoad
{
events = [[self getEvents] retain];
}
- (void)dealloc
{
[events release];
[super dealloc];
}
- (NSArray*)getEvents
{
NSMutableArray *response = [[[NSMutableArray alloc] init] autorelease];
//Some sql
while(sqlite3_step(statement) == SQLITE_ROW)
{
Event *event = [[[Event alloc] init] autorelease];
event.subject = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 0)];
[response addObject:event];
}
return response;
}
Update
A lot of you are saying the code is fine which is a plus. I dont manipulate events elsewhere - I have removed any code that does to try and single out the crash. Perhaps its in the parent view?
This is the click event that pushes the EventsViewController:
- (void)eventsClick:(id)sender
{
EventsViewController *eventsViewController = [[EventsViewController alloc] initWithNibName:#"EventsViewController" bundle:nil];
eventsViewController.anywhereConnection = anywhereConnection;
eventsViewController.contact = contact;
[[self navigationController] pushViewController:eventsViewController animated:YES];
[eventsViewController release];
}
The crash is actually happening when I return to the parent view. (I think it is considered a parent in this scenario). But perhaps the [eventsViewController release] just triggers dealloc in the EventViewController.

Have you considered just refactoring your code to use ARC? It works with iOS 4 and up and will make your life a lot easier. There are plenty of tutorials out there that will guide you how to do it, and will remove the need to manually figure out the nuances of memory management.

If your Events object has property 'subject' set as assign, then the results of stringWithUTF8String: will not be retained. (Same thing if Events is a C++ object.)
The stringWithUTF8String: method returns an auto-released object that will be released at the next turn of the event loop.

There is a huge difference when you reference a variable via "self", and when you don't.
When you use
events = [[self getEvents] retain];
the memory allocated in getEvents never gets stored in the class property and is basically a leak.
You need to use
self.events = [self getEvents]; // no need to use retain if property is correctly defined.
Then
[events release];
should work fine.

try putting
events = nil;
in dealloc.

Related

iphone: How to solve NSArray memory Leak?

I am releasing NSArray and NSMutableArray but its show memory leak. while ZoneData code is like this
-(ZoneData*) initWithZoneName:(NSString *)zoneNameIn SdName:(NSString *)sdNameIn eCount:(NSString *)eCountIn iCount:(NSString *)iCountIn StandLat:(NSString *)standLatIn StandLong:(NSString *)standLongIn
{
self = [super init];
if (self)
{
zoneName = [zoneNameIn copy];
lsdName = [sdNameIn copy];
leCount = [eCountIn intValue];
liCount = [iCountIn intValue];
standLat = [standLatIn copy];
standLong = [standLongIn copy];
}
return self;
}
how to solve this?
The problem is your instance variables. In your -init, you are correctly assigning them to copies of the strings from the array. However, you need t also release them in -dealloc.
-(void) dealloc
{
[zoneName release];
[lsdName release];
[standLat release];
[standLong release];
[super dealloc];
}
Now, you may be asking why the leaks tool is telling you the leaks are where you create the NSArray with the strings in it instead of the init method. The reason is that -copy for immutable objects is optimised to do nothing except send retain to self. So those copies you have as instance variables are in reality the same objects as was created by -componentsSeparatedByString:
componentsSeparatedByString: returns an autoreleased NSArray. You are not supposed to release that yourself, but the closest NSAutoreleasePool will do that for you. In line 61 you are overreleasing the array.
If you are concerned about the memory usage while performing the loop you can clear autoreleased objects in each iteration of the loop:
for (...)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// your loop contents.
[pool drain];
}

Memory leak of an NSMutableArray using Instruments

According to the leak instrument in XCode it's saying this line is giving a memory leak (100%)?
self.unsentPatients = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
I'm correctly releasing etc. on dealloc (which is definitely being ran) so I don't understand where I am going wrong?
It's only a small leak and Analysis doesn't come up with anything, but nonetheless it's still a leak.
Kind regards,
Dominic
There are many things wring with this code.
I'm assuming that the property is retaining the value, then you should not assign the value the way you are doing now, but more like:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
self.unsentPatients = temp;
[temp release], temp = nil;
or
self.unsentPatients = [[[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]] autorelease];
You should also avoid using the self. syntax in dealloc or init, which will call a mutator.
In multithreaded environment this could give problems.
So the correct dealloc would be:
- (void) dealloc {
[unsentPatients release], unsentPatients = nil;
[super dealloc][;
}

iPhone - Objective-C - Memory Leak with initWithArray

I am using the code below to set my two NSArray ivars:
The issue is, I keep getting a memory leak on the following lines:
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
Is this not the correct way to set ivars from an existing NSArray of items? Any help would be appreciated. I've also tried to autorelease the above two lines, but when I actually access them in another method I get an error that they've already been released.
I have included my Interface and Implementation code below:
Interface .h:
NSArray *followingFriendsArray;
NSArray *followerFriendsArray;
#property (nonatomic, retain) NSArray *followingFriendsArray;
#property (nonatomic, retain) NSArray *followerFriendsArray;
Implementation .m:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
This is how I need to access the arrays:
- (void)followersButtonTapped:(id)sender {
FollowingVC *fvc = [[FollowingVC alloc] initWithNibName:#"FollowingViewController" bundle:nil];
fvc.friends = followerFriendsArray;
[self.navigationController pushViewController:fvc animated:YES];
[fvc release];
}
I release my two ivars in the following way as per usual:
- (void)viewDidUnload {
self.followingFriendsArray = nil;
self.followerFriendsArray = nil;
[super viewDidUnload];
}
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
I mean the code works just fine, it's just that I'm concerned about said memory leaks when I run the "Leaks" performance tool.
OK
you should not use autorelease in this case, but you have to release the arrays by calling :
[followingFriendsArray release];
[followerFriendsArray release];
you can do it:
when you don't need to use them any more.
in the dealloc method in your .m file.
option 2looks like that -
- (void)dealloc {
[followingFriendsArray release];
[followerFriendsArray release];
[super dealloc];
}
BTW -
if you don't manipulate the arrays after creating them (add / remove objects) you should use an immutable array (NSArray).
Good Luck
Your method handlerGetFollowingInformation is assigning new values to followingFriendsArray and followerFriendsArray without releasing the previous contents. If you call this method more than once on the same instance you will leak.
CRD is right that the arrays are not released inside the handlerGeFollowingInformation method but the fix is maybe overkill. What you need to do is to use self. so that the setter method is called which does that automatically. You could should look like this:
- (void)handlerGetFollowingInformation:(id)value {
BOOL success = [Utility checkWebServiceErrors:value controller:self.navigationController];
if (success) {
Friend *friend = (Friend *)value;
self.followingFriendsArray = [[NSArray alloc] initWithArray:friend.Following];
self.followerFriendsArray = [[NSArray alloc] initWithArray:friend.Followers];
}
}
Easy fix but hard to spot and I ran into this issue over and over again especially when I started to dealloc are the properties.
-Andy

Why Instruments report a leak?

I am developing an iphone app. Instruments reported a leaked object ServiceTypes. Below is the relevant code. Does anyone have any ideas? Thanks a lot for your help.
ServiceTypes *serviceTypes = [[ServiceTypes alloc] init];
if ([userConnection getServiceTypes:serviceTypes]) {
if ([serviceTypes.types length] > 0) {
NSArray *array = [[NSArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString: SERVICE_TYPE_DELIMITOR]];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:array];
[array release];
}
}
[[self typesTableView] reloadData];
[serviceTypes release];
It doesn't look like serviceTypes is being leaked. From the code you posted, serviceTypes is always released at the end of the method, and it doesn't appear to be retained anywhere in your sample. My question is: what happens inside getServiceTypes:. Does that method retain the serviceTypes parameter?
One more thing. If serviceRequestTypes is an instance variable (and it looks like it is), then you may be leaking memory by reassigning it without releasing the existing serviceRequestTypes object first. You should either rewrite serviceRequestTypes to be a property and use a synthesized accessor or make sure to release it every time before assigning. If its current value is nil, no big deal; the release message will simply be ignored. For example:
[serviceRequestTypes release];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString:SERVICE_TYPE_DELIMITER]];

iPhone app memory leak

Any idea why this code gives me a memory leak? As you can see, I'm running out of ideas as to what I can do to stop it.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSArray *allSketches = [project.sketches allObjects];
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:allSketches];
if(sketchesArray != nil) [sketchesArray release];
[self setSketchesArray:temp];
[allSketches release];
allSketches = nil;
[temp release];
temp = nil;
}
I also release sketchesArray inside viewDidDissapear. I'm not using viewDidLoad and dealloc to init/release these objects as what I am doing requires me to use viewWillAppear and viewDidDissapear.
Thanks
Fixed it by using this instead:
NSArray *allSketches = [project.sketches allObjects];
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:allSketches];
[self setSketchesArray:temp];
[temp release];
Though I remember doing that and it didn't work before... Strange... There appear to still be some memory leaks coming from CoreGraphics though. Is that normal?
Is this being released somewhere else when you are done with it?
[self setSketchesArray:temp];
Specifically, you are releasing sketchesArray in this function, but do you do that elsewhere when you are done with the view?
I can't see the leak, but you've got a couple of probable over-releases.
The release of a non-nil sketchesArray should be managed inside setSketchesArray. And it doesn't look like you have local ownership of allSketches either...