代码之家  ›  专栏  ›  技术社区  ›  Jonathan

nsOperation(s)仅在iOS 3设备上泄漏

  •  2
  • Jonathan  · 技术社区  · 14 年前

    我有一些nsOperations子类来处理coredata导入。我相信我已经勾选了大部分非主流的问题

    • 我在中创建了自己的自动释放池 main 方法
    • 我创建了一个 NSManagedObjectContext 为每个 操作

    这些操作加载到nsOperationQueue中,最大并发操作数设置为1。

    该代码在iOS 4.0.1上工作得很好,但是在iOS 3.1.3设备上,会收到很多日志消息,如下所示

    *** _NSAutoreleaseNoPool(): Object 0x5f926c0 of class NSCFDictionary autoreleased with no pool in place - just leaking
    

    nsOperation子类主方法

    -(void) main{
    
        NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
    
        @try {
        //Start Operation
        //====================================
        NSManagedObjectID       *objID      = nil;
        NSError             *err        = nil;
        id                              user            = nil;
    
        if( !(userID = [self __lookup:[self userID] inContext: [self threadContext]]) ){
    
            //Set the name of the element
            user = [[self threadContext] objectWithID:objID];
            //Update the name
            [user setValue:@"John Doe"  forKey:@"name"];
            [user setValue:@"Hello world" forKey:@"status"];
        }
    
    
        if( ![[self threadContext] save:&err] ){
            DebugLog(@"Couldn't savechanges %@", err);
        }
    
        //====================================
        //End Operation
        }
        @catch (NSException * e) {
            DebugLog(@"Exception %@",e);
        }
        //====================================
    
    
       [pool drain];
    }
    

    这个 __lookup:inContext: 方法

    -(NSManagedObjectID*) __lookup:(id)aID inContext:(NSManagedObjectContext*) aContext{
    
        NSPredicate             *predicate      = nil;
        NSEntityDescription     *entity;
        NSFetchRequest          *fetchRequest   = nil;
        NSError                 *err            = nil;
    
        predicate = [NSPredicate predicateWithFormat:@"userID == %@",aID];
    
        entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:aContext];
    
        fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
    
        [fetchRequest setPredicate:predicate];
    
        [fetchRequest setEntity:entity];
    
        //Only fetch id's for speed
        [fetchRequest setResultType:NSManagedObjectIDResultType];
    
        return [[aContext executeFetchRequest:fetchRequest error:&err] lastObject];
    
    }
    

    大多数其他方法实例方法,即 threadContext 看起来像 _查找:InContext: 方法。我知道我不会为实例方法创建自动释放池,但是根据我对自动释放工作原理的理解,只要这些方法只在主方法内部调用,在 NSAutoreleasePool 已创建,应使用最外部的池。我创建对象(如nsmanagedObjectContext)时比较懒惰,而且在大多数情况下不使用 start 方法

    1 回复  |  直到 14 年前
        1
  •  0
  •   Jonathan    14 年前

    解决了这个问题,这个操作使用 article 戴夫·德林。但是,在可能的情况下,我尽量不剪切和粘贴其他人的代码,这样我就可以过滤我在自己的代码中放入的内容。

    结果我忘了加这张支票

    if( ![NSThread isMainThread] ){
        [self performSelectorOnMainThread:@selector(start) 
                               withObject:nil 
                            waitUntilDone:NO];
        return;
    }
    

    从而确保 start 方法在主线程上运行,其中 NSAutoreleasePool 已经存在。简单的错误,简单的解决方法。