Issues with memory leaks

I have severals leaks and don´t know how to solve it, I am using ARC.


Could someone explain me what is wrong?


The issue is with the NSNumbers contained in the NSDictionaries that are in theNSArray.






#import "SimpleOperation.h"

#import "AppDelegate.h"

#import "Model+Create.h"


@interface SimpleOperation()

@property(nonatomic, strong) NSNumber * max_id;

@end

@implementation SimpleOperation

- (void)main{

@autoreleasepool {

[self executeFetchWithMax_id:self.max_id];

}

}

- (instancetype)initWithMax_id:(NSNumber*)max_id{

if (self = [super init]){

_max_id = max_id;

}

return self;

}

- (void)executeFetchWithMax_id:(NSNumber*)max_id{

__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

__block NSManagedObjectContext *writerManagedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] writerManagedObjectContext];

__block NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

temporaryContext.parentContext = managedObjectContext;


temporaryContext.undoManager = nil;



__block Model *model = nil;


[temporaryContext performBlock:^{


NSArray *statuses= @[@{@"id": @648186162016854016}, @{@"id": @648186162016854017}, @{@"id": @648186162016854018}, @{@"id": @648186162016854019}];

for(NSDictionary *statusDictionary in statuses){

model = [Model modelWithInfo:statusDictionary inManagedObjectContext:temporaryContext];

}


NSError *error = nil;

if (![temporaryContext save:&error]){

abort();

}

[managedObjectContext performBlock:^{

NSError *error = nil;

if (![managedObjectContext save:&error]){

abort();

}

[writerManagedObjectContext performBlock:^{

NSError *error = nil;

if (![writerManagedObjectContext save:&error]){

abort();

}

}];

}];

}];

}

@end

Have you used the Leaks template? That will show you the leaks in your app and where they are coming from, as well as what callstacks were causing retains/releases to occur on that object.

Hello , I used the Leaks template, I tried to upload some pictures but looks like this new forum do not allow it.


The leaks are for each one of the NSNumbers stored in the following array:


NSArray *statuses= @[@{@"id": @648186162016854016}, @{@"id": @648186162016854017}, @{@"id": @648186162016854018}, @{@"id": @648186162016854019}];


Ans is due to the creation of CoreData Objects inside this fast enumeration:


for(NSDictionary *statusDictionary in statuses){

model = [Model modelWithInfo:statusDictionary inManagedObjectContext:temporaryContext];

}


This is the code for create the CoreData Objects:


#import "Model+Create.h"

@implementation Model (Create)

+(Model*)modelWithInfo:(NSDictionary*)dictionary inManagedObjectContext:(NSManagedObjectContext*)context{


Model *model = nil;

NSNumber *id_number = [dictionary valueForKey:@"id"];


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id_number == %@", id_number];


NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Model"];

request.predicate = predicate;

NSError *error =nil;

NSArray *results = [context executeFetchRequest:request error:&error];

if ([results count]){

model = [results firstObject];

}else{

model = [NSEntityDescription insertNewObjectForEntityForName:@"Model" inManagedObjectContext:context];

model.id_number = id_number;

}

return model;

}

@end

I cannot solve the issue, I discovered that If I change:


NSPredicate *predicate = [NSPredicate predicateWithFormat:@"id_number == %@", id_number];


with:


NSPredicate *predicate = nil;


The leaks disappear.


How could I use the [NSPredicate predicateWithFormat:@"id_number == %@", id_number] without leaks?

When an object is leaked, it's either all alone in the world or it belongs to some set of objects that point at one another but are not pointed to by the rest of your objects (it's a little lonely island of objects). Usually, it's the latter case. You want to look at the root object being leaked, and figure out why it is leaked. That's where the retain/release history of that object will tell you who did a retain on the object, never release'd it, and then lost its reference to that object. Often that will be one of your own objects, but not always. It's unlikely that NSNumber or NSPredicate are buggy and leaking memory.


Debugging the particular problem you are encountering in your app is beyond the scope of this forum. I would recommend watching past WWDC videos about Instruments and memory debugging to get a better sense of using the tool and diagnosing problems with it more quickly. Hopefully those help.

If you have memory leaks from Core Data, then you're supposed to follow the instructions for Core Data memory management for reducing memory overhead: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/CoreData/Performance.html#//apple_ref/doc/uid/TP40001075-CH25-SW10


Core Data relationships get represented as strong properties. As a result, if you load a hierarchy of entity values into memory, that can create strong reference cycles. If you get those memory cycles, you have use methods described under "Reducing Memory Overhead" to unload the objects so that the reference cycles break.

Thank you both for yours answers.


I already watchied past WWDC videos, and there are not memory cycles in the code, also for the test I am using a single CoreData Object withouth relationships to isolate the issue.


I realized that the leaks are due to the use of multiple ManagedObjectContexts


Using Multiple ManagedObjectContext generate leaks:


// AppDelegate.m


- (NSManagedObjectContext *)managedObjectContext{

if (_managedObjectContext != nil) {

return _managedObjectContext;

}

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

_managedObjectContext.parentContext = [self writerManagedObjectContext];

return _managedObjectContext;

}


- (NSManagedObjectContext *)writerManagedObjectContext{

if (_writerManagedObjectContext != nil) {

return _writerManagedObjectContext;

}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

if (coordinator != nil) {

_writerManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[_writerManagedObjectContext setPersistentStoreCoordinator:coordinator];

}

_writerManagedObjectContext.undoManager = nil;

return _writerManagedObjectContext;

}


- (void)executeFetchWithMax_id:(NSNumber*)max_id{

__block NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

__block NSManagedObjectContext *writerManagedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] writerManagedObjectContext];

__block NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

temporaryContext.parentContext = managedObjectContext;

temporaryContext.undoManager = nil;

__block Model *model = nil;

[temporaryContext performBlock:^{

NSArray *statuses = @[@{@"id": @648186162016854016}, @{@"id": @648186162016854017}, @{@"id": @648186162016854018}, @{@"id": @648186162016854019}];


for(NSDictionary *statusDictionary in statuses){

model = [Model modelWithInfo:statusDictionary inManagedObjectContext:temporaryContext];

}


NSError *error = nil;

if (![temporaryContext save:&error]){

abort();

}

[managedObjectContext performBlock:^{

NSError *error = nil;

if (![managedObjectContext save:&error]){

abort();

}

[writerManagedObjectContext performBlock:^{

NSError *error = nil;

if (![writerManagedObjectContext save:&error]){

abort();

}

}];

}];

}];

}


Using the normal ManagedObjectContext do not generate leaks:

// AppDelegate.m

- (NSManagedObjectContext *)managedObjectContext {


if (_managedObjectContext != nil) {

return _managedObjectContext;

}


NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

if (!coordinator) {

return nil;

}

_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

[_managedObjectContext setPersistentStoreCoordinator:coordinator];

return _managedObjectContext;

}

// SimpleOperation.m


- (void)executeFetchWithMax_id:(NSNumber*)max_id{


NSManagedObjectContext *managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];

managedObjectContext.undoManager = nil;

Model *model = nil;

NSArray *statuses = @[@{@"id": @648186162016854016}, @{@"id": @648186162016854017}, @{@"id": @648186162016854018}, @{@"id": @648186162016854019}];


for(NSDictionary *statusDictionary in statuses){

model = [Model modelWithInfo:statusDictionary inManagedObjectContext:managedObjectContext];

}

NSError *error = nil;

if (![managedObjectContext save:&error]){

abort();

}

}



At this point, I don´t know what could I do to solve the leaks while using multiple ManagedObjectContexts.

This issue has actually been encountered by quite a number of people. There is a radar here. Any updates or suggested workarounds?

Issues with memory leaks
 
 
Q