Memory issue iphone - iphone

I've never encountered such issue before.. And now i don't know how to handle this, and hoping for some help.
I am pushing a view controller(lets say exampleViewController) to the navigation controller. In my exampleViewController on viewdidload i add an imageview with an image. On dealloc i remove this imageview from superview, then release any retained views. The instruments leak tool doesn't show any leaks, but when i open instruments- "activity monitor" and then i see that when i push my exampleViewController real memory increases in 5 MB, and when i pop my exampleViewController, memory only decreases in 3 MB.. So if i push and pop this exampleViewController a lot of times, i get a memory warning and after that app quits.
I'm definitely doing something wrong, because other view controllers behave as expected. So the problem is i don't know what am i doing wrong, and hope for you guys to suggest some ways of how i could track down what is causing this.
I have tried some tools in instruments like alloc tool and then marking heap, and some similar things, but that doesn't show what gets leaked :/
Thanks in advance!!
EDIT:
Now when marking heaps in instruments it seems executeFetchRequest: is leaking, Am i doing something wrong?
+ (Question *)getQuestionWithId:(NSString *)questionId
{
Question *resultQuestion = nil;
AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
//geting context from appdelegate
NSManagedObjectContext *context = appDelegate.managedObjectContext;
//form fetch request with predicate
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Question"
inManagedObjectContext:context];
NSPredicate *query = [NSPredicate predicateWithFormat:#"questionId=%#",questionId];
NSPredicate *query1 = [NSPredicate predicateWithFormat:#"type='ke'"];
NSPredicate *predicates = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:query,query1, nil]];
[fetchRequest setPredicate:predicates];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
resultQuestion = [fetchedObjects lastObject];
return resultQuestion;
}

Might be, that if your image is loaded with imageNamed, the cache doesn't get emptied on dealloc. Have you tried loading the image with
UIImage *image = [UIImage imageWithContentsOfFile:path];
instead of using
myImageView.image = [UIImage imageNamed:#"someImage.png"]
Of course this might only help "if" you use imageNamed.

...On dealloc i remove this imageview from superview...
Never do this in -(void)dealloc, as this method is supposed for memory management.
Remove the imageview in -(void)viewWillDissappear instead (if you really need this). As about your problem, read this, I believe your issue is somewhere beyond the imageView you are talking about.

Related

Memory leak after second viewing of tableview

I have two UITableViewControllers. I'm pushing to the second one and calling the following method in viewDidLoad.
The second time I dispose of this view and go back to the first view, I get a memory leak.
Instruments says the problem's on the last line of the following method.
- (void)fetchRecords {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:#"Articulation" inManagedObjectContext:[self managedObjectContext]]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"articulationGroup == %#", selectedArticulationGroup];
[request setPredicate:predicate];
static NSArray *sortDescriptors = nil;
if (!sortDescriptors)
sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:#"text" ascending:NO] autorelease]];
[request setSortDescriptors:sortDescriptors];
NSError *error = nil;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];
if (!fetchResults)
NSLog(#"no fetch results ArticulationsViewController, error %#", error);
[request release];
self.articulationsArray = [NSMutableArray arrayWithArray:fetchResults];
}
I've got no idea... going to bed :'(
For one thing, you're leaking your sortDescriptors array if you take the allocation branch.
<soapbox> I strongly recommend you use curly braces around all if/else blocks even if they only have one line - these bugs are very difficult to find after the fact</soapbox>
Please post your dealloc method and the ivar declarations.
Well, I notice two things which might be correct but I wanted to ask about anyway.
First of all, ur asking in the if statement: if (!fetchResults). That would mean fetchResults possibly doesn't exist. Still, you try to initialize an array with that.
Secondly, I don't know how you allocated articulationsArray, but does changing the line into self.articulationsArray = [[NSMutableArray alloc] initWithArray:fetchResults]] have any effect?
Why is your sortDescriptors array static? Typically, you would do something like this:
NSSortDescriptor *textSort = [[NSSortDescriptor alloc] initWithKey:#"text" ascending:NO];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:textSort]];
[textSort release];
Also, after if (!fetchResults) you shouldn't save your array, but do something like this:
if (!fetchResults)
{
NSLog(#"no fetch results ArticulationsViewController, error %#", error);
}
else
{
NSMutableArray *articulationsArray_tmp = [fetchResults mutableCopy];
self.articulationsArray = articulationsArray_tmp;
[articulationsArray_tmp release];
}
[request release];
Also note how you could set the articulationsArray differently. One should always be careful with these NSMutableArrays ... :)
This block is completely unnecessary and it is dangerous:
static NSArray *sortDescriptors = nil;
if (!sortDescriptors)
sortDescriptors = [[NSArray alloc] initWithObject:[[[NSSortDescriptor alloc] initWithKey:#"text" ascending:NO] autorelease]];
[request setSortDescriptors:sortDescriptors];
Any static object is dangerous to memory and you use them only in special cases. Why nail an array with only a local scope to a specific address/block? All this can be replaced with one line:
[request setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortWithKey:#"text" ascending:NO]]];
... and its done.
This line is probably unnecessary and likely to cause problems later:
self.articulationsArray = [NSMutableArray arrayWithArray:fetchResults];
Why would you need a mutable array of fetched objects? You can't really add or remove anything from the array directly while maintaining your graph integrity without refetching.
Just:
self.articulationsArray = fetchResults;
will work fine for most cases.
The more objects you create, the more chances for a leak you create. Keep things as simple as possible.
Well... I feel like a goose.
When I popped back to my first tableViewController, I wasn't releasing articulationsArray.
I was using
- (void)viewDidUnload {
[self.articulationsArray release];
}
When I should have been using:
-(void)viewDidDisappear:(BOOL)animated {
[self.articulationsArray release];
}
ViewDidUnload, was never being called.
Thanks for your help everyone.

Memory leak problem and i need help #1

I am very new at this and seems to have a leak in this piece of code that i cannot fix:
The Instruments shows on this line with a 100%:
NSMutableArray *read_Question = [[NSMutableArray alloc] initWithCapacity: 0];
I have tried all kind of things but not been able to fix it.
Anyone nice that can advice me how to proceed?
- (NSMutableArray *)readQuestion: (int)questionNr {
NSMutableArray *read_Question = [[NSMutableArray alloc] initWithCapacity: 0];
NSError *error;
//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) {
managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext]; }
// Define qContext
NSManagedObjectContext *qContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"questions" inManagedObjectContext:qContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
if ([[info valueForKey:#"idQ"] intValue] == questionNr) {
[read_Question addObject:[info valueForKey:#"question"]];
[read_Question addObject:[info valueForKey:#"qRightAnswer"]];
[read_Question addObject:[info valueForKey:#"qWrongAnswer1"]];
[read_Question addObject:[info valueForKey:#"qWrongAnswer2"]];
}
}
[fetchRequest release];
return [read_Question autorelease];
}
It seams that you are returning the object only inside the if statement. Meaning that if the if statement is false you will not autorelease the array. Or maybe you didn't paste the entire method. Let me know. Instruments is sometimes tricky.
This is a dupe of your other question Memory leak problem and i need help #1
When i did release i got into trouble,
of course. I did try to change the
names on the three and do release so
there was unique names but that did
not work.
Changing the names across three different files? That won't do anything and it indicates that you haven't entirely wrapped your head around objects, pointers, and memory management.
The Objective-C and Memory Management guides will help.
Could this be the reason for the leak
i have in this .m file?
Nope -- as I answered in the other question, the leak is most likely because you retain the object that is returned by that method and then don't release it anywhere.
Instruments is telling you were the leaked object was allocated, not where it was necessarily leaked.
While you may not be autoreleasing the array in all cases on return from that method, you might also be retaining it somewhere else and not balancing that retain with a release.
I am assuming you set the property managedObjectContext to "retain". Change the line to this (include "self" so that it gets retained):
if (self.managedObjectContext == nil) { self.managedObjectContext = [(FamQuiz_R0_1AppDelegate *)
[[UIApplication sharedApplication] delegate] managedObjectContext]; }
Then add your release back in.
Since I believe the code from picciano will fix the issue of the openingsposter, here a small explanation why it should fix the issue.
If you give a property the retain attribute, it will create an accessor method that looks somewhat like this (simplified):
#property (nonatomic, retain) NSValue *value;
- (void)setValue:(NSValue *)aValue {
value = [aValue retain];
}
Only when the retainCount reaches 0 an object is released, using retain, alloc and copy increases the retainCount. Remember: only when using the accessor method the retain actually happens (besides using alloc, retain and copy directly). The accessor method is usually called when using one of the following methods:
// the 2 most obvious ways to call the accessor methods ...
object.value = someValue;
[object setValue:someValue];
You created a retain property in your code, yet you didn't use the accessor method, so the object was never retained.
// no accessor used here ...
managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
If you would release it from this point on, it would cause a crash, since the retainCount would actually become -1 at some point (since it never got to 1 in the first place). Therefore you should set the property like this:
// the dot-notation syntax to make use of the accessor method ...
self.managedObjectContext = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
or (in my opinion preferably):
// making use of the accessor method directly, which is very unambiguous ...
NSManagedObjectContext *context = [(FamQuiz_R0_1AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
[self setManagedObjectContext:context];
This way you can be sure the retain actually happens.
The second notation to accessor setters is in my opinion superior and I consider it good habit to use it for setting properties whenever possible. Read more about people who share this opinion and their reasoning on the following sites:
Cocoa Is My Girlfriend
The Big Nerd Ranch

Memory leak in cocoa touch with a mutableCopy

I'm trying to resolve a memory leak but I can't find any solution.
Instruments says that there is a leak in this method:
- (void)refreshData {
Sn0werSp33dAppDelegate *appDelegate = [[Sn0werSp33dAppDelegate alloc] init];
NSFetchRequest *coreDataNewsFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"News" inManagedObjectContext:managedObjectContext];
[coreDataNewsFetchRequest setEntity:entity];
self.managedObjectContext = appDelegate.managedObjectContext;
self.newsArray = [[managedObjectContext executeFetchRequest:coreDataNewsFetchRequest error:nil] mutableCopy];//Intruments says that here is the memory leak :(
[appDelegate release];
[coreDataNewsFetchRequest release];
[entity release];
}
newsArray is declared in my .h as an NSMutableArray and it has a property:
#property (nonatomic, retain) NSMutableArray *newsArray;
I've tried many things but at all times, that things weren't working.
I'm running XCode 3.2.5 with iPhone SDK 4.2.1 and Instruments 2.7.
When you do
self.newsArray = something;
that something is retained, because you added retain to the newsArray property.
But mutableCopy also returns an object with a retain count increased by 1. So after the method finishes, your newsArray has a retain count one higher than what you really want, which is the memory leak that was detected.
Solution: Replace the line where you assign self.newsArray with
self.newsArray = [[[managedObjectContext executeFetchRequest:coreDataNewsFetchRequest error:nil] mutableCopy] autorelease];
mutableCopy makes a copy and retains it, so you need to release the copy you've created. Try changing this:
self.newsArray = [[managedObjectContext executeFetchRequest:coreDataNewsFetchRequest
error:nil] mutableCopy];
To this:
self.newsArray = [[[managedObjectContext executeFetchRequest:coreDataNewsFetchRequest
error:nil] mutableCopy] autorelease];
As an aside, creating a new object of your app delegate class is a little unusual and might not give you the result you expect. Conventionally you instantiate one app delegate (by default this is done for you in MainWindow.xib) and then refer to it throughout your app using:
FooAppDelegate *appDelegate = (FooAppDelegate*)[[UIApplication sharedApplication] delegate];

Core Data Memory Leak - iPhone iOS4

I desperately need help with a memory leak in my iPhone app. The app is ready to submit to the app store, is stable, has no memory leaks at all in iPhone simulator or Clang ... but seems riddled with them on my iPod Touch.
They all seem to stem from managedObjectModel when I'm trying to retrieve data from Core Data.
The Core Data code in my app was automatically created by Xcode a while back, I've noticed that the code has since changed when you get xcode to generate it ... I've tried with the old and new but it makes no difference.
If I comment out the following code, the problem goes away ... can anyway see what's wrong with it? I've spent 9 hours on this so far and just can't figure it out!
NSString *entityForName = [[NSString alloc] initWithString:#"OfflineSettings"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityForName inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
[entityForName release];
NSSortDescriptor *sortById = [[NSSortDescriptor alloc] initWithKey:#"Id" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortById]];
[sortById release];
NSError *error;
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(#"Error fetching");
}
int intId = -1;
if ([mutableFetchResults count] == 0) {
TTDERROR(#"No id has been saved to offline settings");
} else {
OfflineSettings *offlineSettings = (OfflineSettings *)[mutableFetchResults objectAtIndex:0];
intId = [offlineSettings.Id intValue];
}
[mutableFetchResults release];
[request release];
The leak specifically seems to be on this line:
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
.. and the code for [self managedObjectContext] is as follows in case it helps ..
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
I'm really at a loss, so I would be so grateful for some help!
Steven
You don't need the mutable copy. executeFetchRequest: returns an autoreleased static array and you're not mutating the array. (I keep seeing this. Must be in an example somewhere.) Likewise, creating the entityForName NSString is pointless. Just put the string literal in the entityForName: to eliminate another possible source of error.
Niether of these are the likely source of the leak but you should remove them anyway.
As a rule of thumb, if you have troubles on device but not simulator or on one hardware but not others, then the problem is in a library/framework that is not properly compiled for the hardware where the error occurs. There really isn't any type of coder error that leaks in one environment but not others. When we make a mistake, it's universal.
It's also possible for resources such as images and sounds to behave differently because different devices use different graphics and audio hardware. That, however, is rather rare.
If you run the code through Instruments it should tell you exactly what object is leaking.

iPhone NSCFString leaks in fetchRequest

In the following code:
- (NSMutableArray *) fetchNotesForGroup: (NSString *)groupName {
// Variables declaration
NSMutableArray *result;
NSFetchRequest *fetchRequest;
NSEntityDescription *entity;
NSSortDescriptor *sortDescriptor;
NSPredicate *searchPredicate;
NSError *error = nil;
// Creates the fetchRequest and executes it
fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
entity = [NSEntityDescription entityForName:#"Note" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"noteName" ascending:YES] autorelease];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[fetchRequest setReturnsDistinctResults:YES];
searchPredicate = [NSPredicate predicateWithFormat:#"categoryName like %#", groupName];
[fetchRequest setPredicate:searchPredicate];
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:#"noteName"]];
result = [[managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
// Variables release
return result;
}
... I Fetch notes for a given categoryName. When I'm running Instruments, it says that a NSCFString is leaking.
I know leaks are mean for iPhone developers... but I don't have any idea on how to plug this one.
Any clues? All help is welcome.
Thanks a lot!
Your problem is this:
result = [[managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
// Variables release
return result;
mutableCopy returns an owning reference (ie, an object with a +1 retain count), which you are responsible for (auto)releasing. You don't, and you then relinquish the reference, which means you've leaked the array.
Use return [result autorelease]; instead.
First of all, Instruments may not be always accurate.
It can report leaks on some special case, just because it don't see you are actually releasing the object elsewhere.
It's also possible that some parts of the CF have leaks.
What I can see in your code is that you are using auto-released objects.
You're temporary objects will have a long life-cycle.
What append if you release them explicitly instead, just before the method's return?
You are also returning a copy of an object.
You have to make sure that object is released at some point.
It may be much better to return an auto-released object, and let the calling method decide if the object should be retained.
Since you don't create any strings, the leaking string is most likely one of the strings that ends up inside the fetch request and it is most likely the fetch request that is actually leaking. (The call stack shown in Instruments should confirm this.)
I don't think you have an actual leak but by doing this:
fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
... you are allowing the fetchRequest to live beyond the scope where it was defined Instruments will interpret that as a leak.
Autorelease actually makes objects live longer than direct release because it causes objects to hang around until the outer autorelease pool is drained. For example, if you create object-B inside object-A and return it to object-C autoreleased, object-B will stay alive long after object-A has been deallocated even if object-C never retains it. (Although it will eventually die at an unpredictable moment.)
Autorelease is not a convenience method for retaining. It has a specific purpose of retaining objects that are being passed between other objects. If your not doing this, don't use autorelease.
If you do this:
fetchRequest = [[NSFetchRequest alloc] init];
// ...
[fetchRequest release];
... your leak will go away.
You might, however, want to do this:
return [result autorelease];
... to ensure that the result array lives long enough to be retained by another object.