premature dealloc in ARC based app

У меня проблема, которая, похоже, заключается в преждевременном освобождении неиспользуемого объекта в приложении на базе ARC. Я пытаюсь создать папку на FTP-сервере. Соответствующие части кода приведены ниже; сначала я опишу проблему.

Проблема в том, что отладочный вывод в

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode

методе никогда не вызывается.

Вместо этого я просто получаю ошибку _EXC_BAD_ACCESS_. В процессе отладки я обнаружил две вещи:

  1. ошибка появляется только если выполняется следующая строка кода (метод createDir):

    [ftpStream open];
    

если это сообщение не отправляется, остальная часть кода не имеет смысла - но и сбоя не происходит...

  1. Я отследил EXC_BAD_ACCESS с помощью NSZombieEnabled: При включенных зомби-объектах GDB выдает следующую информацию отладчика:

     *** -[FTPUploads respondsToSelector:]: сообщение отправлено деаллоцированному экземпляру 0x9166590
    

Указанный адрес 0x9166590 является адресом моего объекта FTPUploads. Похоже, что делегат потоков деаллоцируется до того, как он сможет обрабатывать сообщения.

Почему система деаллоцирует используемый объект? Как я могу предотвратить преждевременное освобождение объекта?

код:

FTPUploads.h excerpt:

#import <Foundation/Foundation.h>

enum UploadMode {

    UploadModeCreateDir, 
    UploadModeUploadeData
};

@class UploadDatasetVC;

@interface FTPUploads : NSObject<NSStreamDelegate> {

    @private
    NSString *uploadDir;
    NSString *ftpUser;
    NSString *ftpPass;

    NSString *datasetDir;
    NSArray *files;

    /* FTP Upload fields */
    NSInputStream *fileStream;
    NSOutputStream *ftpStream;
    // some more fields...
    enum UploadMode uploadMode;
    UploadDatasetVC *callback;
}

- (id) initWithTimeseriesID: (int) aTimeseriesID 
             fromDatasetDir: (NSString *) aDir
                  withFiles: (NSArray *) filesArg 
          andCallbackObject: (UploadDatasetVC *) aCallback;

- (void) createDir;

@end

FTPUploads.m excerpt

#import "FTPUploads.h"
#import "UploadDatasetVC"

@implementation FTPUploads

- (id) initWithTimeseriesID: (int) aTimeseriesID 
             fromDatasetDir: (NSString *) aDir
                  withFiles: (NSArray *) filesArg 
          andCallbackObject: (UploadDatasetVC *) aCallback {

    self = [super init];

    if (self) {

        uploadDir = [NSString stringWithFormat: @"ftp://aServer.org/%i/", aTimeseriesID];
        ftpUser = @"aUser";
        ftpPass = @"aPass";

            datasetDir = aDir;
            files = filesArg;

        bufferOffset = 0;
        bufferLimit = 0;

        index = 0;

        callback = aCallback;
    }

    return self;
}

- (void) createDir {

    uploadMode = UploadModeCreateDir;
    NSURL *destinationDirURL = [NSURL URLWithString: uploadDir];

    CFWriteStreamRef writeStreamRef = CFWriteStreamCreateWithFTPURL(NULL, (__bridge CFURLRef) destinationDirURL);
    assert(writeStreamRef != NULL);

    ftpStream = (__bridge_transfer NSOutputStream *) writeStreamRef;
    [ftpStream setProperty: ftpUser forKey: (id)kCFStreamPropertyFTPUserName];
    [ftpStream setProperty: ftpPass forKey: (id)kCFStreamPropertyFTPPassword];

    ftpStream.delegate = self;
    [ftpStream scheduleInRunLoop: [NSRunLoop currentRunLoop] forMode: NSDefaultRunLoopMode];
    // open stream
    [ftpStream open];

    CFRelease(writeStreamRef);
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {

    NSLog(@"aStream has an event: %i", eventCode);

    switch (eventCode) {
        // all cases handled properly
        default:
            // no event
            NSLog(@"default mode; no event");
            break;
    }
}

EDIT: добавлен код создания, который используется в классе UploadDatasetVC:

FTPUploads *uploads = [[FTPUploads alloc] initWithTimeseriesID: timeseries_id 
                                                fromDatasetDir: datasetDir 
                                                     withFiles: files 
                                             andCallbackObject: self];
[uploads createDir];
5
задан Brad Larson 6 February 2012 в 18:07
поделиться