NSArray在setCompletionBlock中泄漏

jod*_*odm 5 memory-leaks objective-c nsoperationqueue ios objective-c-blocks

编辑问题:21/10/2013 20:10 GMT

添加了下面调用方法的方法以及泄漏的对象是"allDBObjects"如果我删除它并将下面的字典更改为"NSMutableDictionary*objectsById",则没有泄漏.

编辑问题:21/10/2013

几天后我没有回到这个问题上.我认为这完全取决于"解除分配问题"(https://developer.apple.com/library/ios/technotes/tn2109/_index.html#//apple_ref/doc/uid/DTS40010274-CH1-SUBSECTION11).我已经使用MKNetworkKit和AFNetworking 1.3.3进行了测试(更改1方法以使用AFNetworking而不是MKNetwork Kit),我仍然在完成块中泄漏这些对象.我在块中没有引用self并且使用AFNetworking我可以看到completionBlock设置为nil并且我试图通过设置[weakOp setCompletionBlock:nil]来手动中断保留周期.

编辑:下面的代码示例我尝试使用属性并将它们引用为weakSelf.我现在已将这些更改为局部变量,但它们仍然泄漏.

有任何想法吗?

原始问题

我使用MKNetworkKit和Core Data接管了一个项目,在通过Leaks in instruments运行项目后,我可以在应用程序的不同位置看到很多泄漏的对象.

调试代码后,我可以看到泄漏的对象是在MKNetworkKit请求(setCompletionBlock :)的回调中发生的2次获取请求.需要完成提取请求以检查是否需要插入或更新数据.

一些进一步的信息 在完成块内部,我得到一个ManagedObjectContext的实例,并使用并发类型"NSPrivateQueueConcurrencyType"创建它,并执行插入我在moc上正确调用"performBlock:".

请指教.

詹姆士

块示例代码:请注意:我已经注释掉了2个获取请求,没有泄漏并将它们放回原因导致数百个对象泄漏,我设置NSDictionary和NSArray的weakSelf属性也是(非原子,强).

- (void) updateDbObjects: (int) page withCallback: (CompletionResultsNumberBlock) callback {  

#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
dispatch_queue_t callerQueue = dispatch_get_current_queue();
#pragma GCC diagnostic warning "-Wdeprecated-declarations"

__weak typeof(self) weakSelf = self;


NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[self createFullPath:urlStr]]];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

    NSManagedObjectContext *moc = [weakSelf managedObjectContextForCurrentThread];
    DataRoot *dataRoot = [DataRoot sharedInstanceInMoc:moc];

    NSArray *returnJSON = JSON[@"object"];
    __block int count = returnJSON.count;

    if (!count)
    {
        dispatch_async(callerQueue, ^{
            callback(0);
        });
        return;
    }

    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"DBObjects"];
    NSError *error;
    NSArray *allDBObjects = [moc executeFetchRequest:fetchRequest error:&error];

    NSMutableDictionary *objectsById = [NSMutableDictionary dictionaryWithObjects:allTeamsArray forKeys:[allTeamsArray valueForKey: GoalTeamObjectAttributes.teamId]];

    for (NSDictionary *rootDict in returnJSON)
    {
        GoalTeamObject *dbObject =  objectsById[rootDict[@"id"]];

        if (dbObject == nil)
        {
            dbObject = [DBObjects insertInManagedObjectContext:dataRoot.managedObjectContext];
        } 

        [weakSelf importStandardParametersFrom:rootDict into:dbObject withPrefix:@""];

    }

    returnJSON = nil;
    objectsById = nil;

    [dataRoot saveContext];

    NSError *childError = nil;

    if ([moc save:&childError]) {

        NSError *parentError = nil;
        if (![moc.parentContext save:&parentError]) {
            NSLog(@"Error saving parent");
        }

        dispatch_async(callerQueue, ^{
            callback(count);
        });

    } else {
        NSLog(@"Error saving child");
    }


} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {

}];

[operation start];

 }
Run Code Online (Sandbox Code Playgroud)

这就是调用此代码的方式:它在循环中递归调用,因为有许多页面的数据.

__block int page = 1;

__weak typeof(self) weakSelf = self;

CompletionResultsNumberBlock loadData;

__block CompletionResultsNumberBlock block_loadData = loadData = ^(int results)
{
    if (results < 100)
    {
        dispatch_async(callerQueue, callback);
    } else {
        [weakSelf updateDbObjects:++page withCallback:block_loadData];
    }
};

[self updateDbObjects:page withCallback: loadData];
Run Code Online (Sandbox Code Playgroud)

Jon*_*ast 0

您可以weakSelf在街区内的某些地方使用,也可以self在其他地方使用。这意味着该块仍将self以强大的方式捕获。

我会尝试首先替换您的块中的所有引用。selfweakSelf

  • 好吧...我仍然在您的区块中看到至少两次对 self 的引用。也许显示重现问题的最简单的代码块会有帮助? (2认同)