0

FTPリクエストを介してサーバーから画像をダウンロードして表示できるアプリを開発しています。ftp 要求はバックグラウンドで実行されています。ダウンロードが完了すると、更新メッセージがビューに送信されます。

I encountered a memory leak when doing the ftp request which has the following features:
1. The memory leak do not happen every time. May be 1 / 7.
2. If I do the ftp request on the main thread, everything is OK.
3. If I do the ftp request on simulator, everything is OK.

私はSIMPLEFTPを使用して ftp ジョブを実行し、リクエストを修正するためにいくつかの変更を行いました。

FtpListService.m では、このファイルは文書リスト情報 (名前、サイズ、変更日) を要求するために使用されます。ここでメモリ リークが発生しています ("####" の行を強調表示しています)。

//This is the method to start a ftp request
- (void)_startReceive
// Starts a connection to download the current URL.
{
    BOOL                success;
    NSURL *             url;
    CFReadStreamRef     ftpStream;

    //don't tap receive twice in a row!
    assert(self.networkStream == nil);     

    // First get and check the URL.
    self.InputUrl = [self.InputUrl stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
    url = [FtpUtil smartURLForString:self.InputUrl];
    success = (url != nil);

    // If the URL is bogus, let the user know.  Otherwise kick off the connection.
    if (!success) {
        DLog(@"Bad ftp url.");
    } else {

    // Create the mutable data into which we will receive the listing.
    assert(self.listData != nil);

    // Open a CFFTPStream for the URL.
    ftpStream = CFReadStreamCreateWithFTPURL(NULL, (CFURLRef) url);

    assert(ftpStream != NULL);

    self.networkStream = (NSInputStream *) ftpStream;

    self.networkStream.delegate = self;
    [self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:RUNLOOPMODEL];

    //This timer will be called to terminate the request which is blocked for a  customed time.
    NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:TIMEOUTFTPLIST target:self
                                                    selector:@selector(listdealTimeOut:) userInfo:nil repeats:NO];

    [[NSRunLoop currentRunLoop] addTimer:timer forMode:RUNLOOPMODEL];

    [self.networkStream open];

    CFRelease(ftpStream);

    }
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
// An NSStream delegate callback that's called when events happen on our 
// network stream.
{
    connected = @"connected";

     switch (eventCode) {            //####################### EXC_BAD_ACCESS 
        case NSStreamEventOpenCompleted: {
            //NSLog(@"NSStreamEventOpenCompleted");
        } break;
        case NSStreamEventHasBytesAvailable: {
             NSInteger       bytesRead;
             uint8_t         buffer[LISTDOCBUFFER];

         // Pull some data off the network.

        bytesRead = [self.networkStream read:buffer maxLength:sizeof(buffer)];
        if (bytesRead == -1) {
            [self _stopReceiveWithStatus:@"Network read error"];
            } else if (bytesRead == 0) {
                [self _stopReceiveWithStatus:@"no more data"];
            } else {
                assert(self.listData != nil);

                // Append the data to our listing buffer.
                [self.listData appendBytes:buffer length:bytesRead];

                [self _parseListData];
            }
        } break;
        case NSStreamEventHasSpaceAvailable: {
            //NSLog(@"NSStreamEventHasSpaceAvailable");
             assert(NO);     // should never happen for the output stream
        } break;
        case NSStreamEventErrorOccurred: {
            DLog(@"NSStreamEventErrorOccurred");
            [self _stopReceiveWithStatus:@"Stream open error"];
        } break;
        case NSStreamEventEndEncountered: {
            DLog(@"NSStreamEventEndEncountered");
            // ignore
        } break;
        default: {
            DLog(@"default");
            assert(NO);
        } break;
    }

}

FtpService.m. ここで、ftp リクエストを行うためのアドレスと試行時間を指定できます。

- (NSArray *)requstServerListInfo:(NSString *)filename tryTime:(int)tryTime
{
    NSArray *result = nil;

   //Create the request ftp path
    NSString* tm = [NSString stringWithFormat:FTPURL];

    if(filename != nil)
        tm = [NSString stringWithFormat:@"%@%@/",FTPURL,filename];

    while (tryTime-- > 0) {

        FtpListService *listService = [[FtpListService alloc] initWithUrl:tm];

        [listService _startReceive];

        //isReceiving will be NO only when : connect error, time out, correctly done job
        //I do not really understand the loop, I just know this will cause the request job to begin
        while (listService.isReceiving) {
            [[NSRunLoop currentRunLoop] runMode:RUNLOOPMODEL beforeDate:[NSDate distantFuture]];
        }

        //if correctly request, dirArray != nil
        if(listService.dirArray == nil) {
            [listService release];
            continue;

        } else {

            result = listService.dirArray;
            [listService release];
            break;
        }
     }

    return result;
}

シングルトンである PGNetConductor.m から始まる ftp ジョブ:

pm = [[PGDataManagement alloc] init];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    result = [pm startNetWork];
}

PGD​​ataManagement は PGNetConductor によって所有されています: @property (nonatomic, unsafe_unretained) PGDataManagement *pm;

私は多くのことを試みましたが、問題を解決できませんでした。誰かが私にアドバイスをくれることを願っています。コードまたは詳細情報が必要な場合は、教えてください。ありがとう!

4

0 に答える 0