繁体   English   中英

NSThread导致iPhone中的内存泄漏

[英]NSThread Causing memory Leaks in iPhone

我在后台线程中明智地上传图像,每个块的大小为512kb,据我所知,我已经使用release,nsautoreleasepool来处理内存泄漏问题。 以下是分块上传图像的代码。

- (void)FetchDataFromDB : (NSNumber *) isOffline
{
 @autoreleasepool {
    @try {
    NSLog(@"FetchDatafromDB");
    isThreadStarted = YES;

    VYukaDBFunctions *vdb = [VYukaDBFunctions getInstance];

    NSMutableArray *fileNames = [vdb GetFileNames:[isOffline integerValue]];
    for(int j=0 ; j<[fileNames count] ; j++)
    {

        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        NSString * filename = fileNames [j] ;
        int _outgoingMsgId = [[vdb SelectMsgId:filename] intValue];
        int  _totalchunk =[[vdb SelectTotalChunk:filename]intValue];
        int currentChunk = [vdb GetCurrentChunk:filename];
    for( int i=currentChunk ; i <= _totalchunk ; i++)
    {

        NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];

        NSString *AsyncRequest = [[NSString alloc] init];
        AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];

        if(![AsyncRequest isEqual:@""])
        {

        BOOL status = [self UploadChunkWise :AsyncRequest : 1 : i : vdb : filename : _outgoingMsgId];
      // AsyncRequest = NULL;
     //  [AsyncRequest release];
        if(status){
            if(i==_totalchunk)
            {
                NSLog(@"Deleting from medialist , FileName :%@", filename);
                [vdb DeleteFromMediaList : filename];

            }
        }
        else{

            [vdb DeleteFromMediaList : filename];
            break;
        }
        }

        [innerPool drain];
    }

        [pool drain];
    }

    [fileNames removeAllObjects];

   // [fileNames release];

    //recurssive call to check any pending uploads..
    if([[vdb GetFileNames:[isOffline integerValue]] count] > 0)
    {
        NSLog(@"Calling Recursively..");
        [self FetchDataFromDB:[isOffline integerValue]];
    }

    }
    @catch (NSException *exception) {

        NSLog(@"Exception caught on Uploading from FetchDataFromDB:%@", exception);

    }
    @finally {

    }
}

 NSLog(@"thread quit ");
 isThreadStarted = NO;
[NSThread exit];

}

-(BOOL) UploadChunkWise :(NSString *) AsyncRequest : (int) count : (int)currentChunk : (VYukaDBFunctions * ) vdb : (NSString *) currentFileName : (int) outgoingMsgId
{

NSHTTPURLResponse *response ;
NSError *error;
//Yes, http
NSMutableURLRequest *httpRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL     URLWithString:@"Url goes here"]];
NSData* data = [AsyncRequest dataUsingEncoding:NSUTF8StringEncoding];

[httpRequest setHTTPMethod:@"POST"];
[httpRequest setHTTPBody:data];

[httpRequest setValue:@"application/xml" forHTTPHeaderField:@"Content-Type"];
NSData *returnedData = [NSURLConnection sendSynchronousRequest: httpRequest returningResponse:&response error:&error] ;
NSString *result= [[NSString alloc] initWithData:returnedData encoding:NSASCIIStringEncoding];
[httpRequest release];

returnedData= NULL;
[returnedData release];
data = NULL;
[data release];

if ([result rangeOfString:@"success"].location != NSNotFound )
{
    NSLog(@" success");
    [vdb DeleteCurrentChunkFromOutgoingTable:currentChunk : outgoingMsgId];
    [result release];
    return YES ;

}
else if ([result rangeOfString:@"fail"].location != NSNotFound )
{
    [result release];
    if (count < 3) {

        return  [self UploadChunkWise :AsyncRequest : count+1 : currentChunk: vdb : currentFileName : outgoingMsgId ];
    }
    else
    {
        NSLog(@" failed");
        [vdb DeleteAllCurrentFileChunksFromOutgoingTable:currentFileName];
        return NO ;
    }

}

return NO;

}

我正在如下启动线程

 [NSThread detachNewThreadSelector:@selector(FetchDataFromDB:) toTarget:self withObject:[NSNumber numberWithInt:0]];

问题是上传9到12个块后,出现内存错误。 我收到4到5次内存警告,然后该应用程序崩溃。在控制台中,我首先在应用程序委托类上获取内存警告,然后是4个扩展UIViewController的类。 为什么我在应用程序委托和其他类型为UIViewController的类上收到警告。如果单独的线程给我内存错误,为什么我必须释放其他类的对象? 我在这里做错了什么? 我无法使用ARC,因为我已将其与不使用ARC的旧代码集成在一起,因此我尝试了明智地启用ARC类,但是这样做并不起作用。 谁能帮助我找出这段代码中是否有内存泄漏。 欢迎提出建议并表示赞赏。

两件事-首先,我看到了这一点:

NSString *AsyncRequest = [[NSString alloc] init];
AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];

这应该合并为:

NSString *asyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];

相反,您正在创建一个新实例,然后立即生成或引用另一个实例。

第二:

您的代码很难阅读,并且不遵循Objective-C smalltalk约定。

变量名称应以lowercase字母开头。 方法名称还应该以小写字母开头。 类名和功能应以大写字母开头。 由于我和许多其他人已经受过训练,可以看到大写字母并认为“类别名称”而不是“可能的变量名称”,因此很难阅读。 仅供参考

最后,您的某些方法采用多个参数,例如上面的参数。 您确实应该为每个参数添加一个前缀,以便于理解该参数的用途。 这个:

[vdb SelectAsyncRequest: PARAMETER : PARAMETER];

如果是,它将看起来更好:

[vdb selectAsyncRequestForParameter: PARAMETER withOtherParameter:OTHERPARAM];

编辑:我也不认为您需要那么多自动发布池。 整个内容已经包装在一个大型自动释放池中。

EDIT2:我还看到了很多不必要的release调用。 在您的UploadChunkWise方法中,您要对*data*returnedData调用release,它们已经隐式自动释放 将对象返回给您的方法将已经拥有所有权并“移交给”您。 本质上,这些方法可以做到这一点:

NSData *data = [[NSData alloc] init];
return [data autorelease];

当您获取它时,如果要保留它,则必须自己retain它,否则它将在方法返回时销毁。

但是,对使用-init创建的NSString *result实例调用release是正确的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM