Memory leak problem and i need help #1

2019-03-01 05:34发布

问题:

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];
}

回答1:

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.



回答2:

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.



回答3:

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.



回答4:

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.



回答5:

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