NSString в пользовательском классе -> добавляется в словарь -> когда возвращается извлеченное значение NSString изменилось? - PullRequest
0 голосов
/ 01 марта 2011

Я пытаюсь передать файл на iphone с помощью OpenAL. Большая часть этого кода основана на превосходном учебнике Бена Бриттена ; однако я попытался сохранить данные в пользовательском классе в словаре, а не в словаре в словаре.

Я настроил пользовательский класс для хранения информации о файле, который я буду передавать в потоковом режиме. Здесь содержится NSString с именем fileName, которая содержит местоположение моего файла. Именно эта переменная меняет свое значение при извлечении. Пользовательский класс определяется так:

@interface DBuffer : NSObject {
    NSString    *fileName   ;
    UInt32      fileSize    ;
    UInt32      bufferSize  ;
    UInt32      bufferIndex ;
    ALenum      bufferFormat ;
    ALsizei     bufferFreq  ;
    BOOL        bufferLoops ;
}

@property (nonatomic, retain) NSString      *fileName       ; *<-----;
@property (nonatomic, assign) UInt32        fileSize        ;
@property (nonatomic, assign) UInt32        bufferSize      ;
@property (nonatomic, assign) UInt32        bufferIndex     ;
@property (nonatomic, assign) ALenum        bufferFormat    ;
@property (nonatomic, assign) ALsizei       bufferFreq      ;
@property (nonatomic, assign) BOOL          bufferLoops     ;


-(void)dealloc ;

@end


@implementation DBuffer

@synthesize fileName    ;
@synthesize fileSize        ;
@synthesize bufferSize      ;
@synthesize bufferIndex     ;
@synthesize bufferFormat    ;
@synthesize bufferFreq      ;
@synthesize bufferLoops     ;


-(void)dealloc
{
    [fileName     release];
    [super dealloc];
}

@end

Каждый звук хранится в словаре так:

-(void)loadFiles 
{
    NSMutableDictionary* tempLibrary = [[NSMutableDictionary alloc] init];

    NSString* fileName = [[NSBundle mainBundle] pathForResource:@"b2" ofType:@"caf"];
    [tempLibrary setObject:[self initializeStreamFromFile: fileName format:AL_FORMAT_STEREO16 freq:44100 ] forKey: @"101" ];
    [fileName release];

    NSString* fileName2 = [[NSBundle mainBundle] pathForResource:@"a5" ofType:@"caf"];
    [tempLibrary setObject:[self initializeStreamFromFile: fileName2 format:AL_FORMAT_STEREO16 freq:44100 ] forKey: @"102" ];
    [fileName2 release];

    self.soundLibrary = tempLibrary;
    [tempLibrary release];
    NSLog(@"load files: tempLibrary %@<%x>", tempLibrary, &*tempLibrary);
    NSLog(@"load files: soundLibrary %@<%x>", soundLibrary, &*soundLibrary);
    NSLog(@"load files: soundLibrary retaincount %d", [soundLibrary retainCount]);
    NSLog(@"load files: tempLibrary retaincount %d", [tempLibrary retainCount]);

    DBuffer *retrieve = [soundLibrary objectForKey:@"101"];
    NSLog(@"retrieve: %@",retrieve.fileName);
    NSLog(@"retrieve retaincount: %d",[retrieve.fileName retainCount]);

}

Он вызывает initializeStreamFromFile, который определен ниже. После того, как он возвращает и добавляет классы в словарь, я делаю проверку, чтобы попытаться извлечь имя файла из словаря с помощью метода экземпляра loadFiles, и он работает нормально, возвращая:

"Получить: / Пользователи / Дэвид / Библиотека / Поддержка приложений / iPhone Simulator / 4,2 / Применения / 7DA24283-8D58-49B8-BBeB-48B08D921367 / OpenALRefine.app / b2.caf "

Какой правильный адрес, такой же, как в журнале в точке инициализации, показанной ниже, и

"восстановить остаток: 2"

// this queues up the specified file for streaming
-(DBuffer*)initializeStreamFromFile:(NSString*)fileName format:(ALenum)format freq:(ALsizei)freq
{
    // first, open the file
    AudioFileID fileID = [self openAudioFile:fileName]; 

    // find out how big the actual audio data is
    UInt32 fileSize = [self audioFileSize:fileID];


    UInt32 bufferSize = kOPENAL_STREAMING_BUFFER_SIZE;
    UInt32 bufferIndex = 0;

    DBuffer* DBufferID = [[[DBuffer alloc] init] autorelease];

    DBufferID.fileName  = fileName ;
    DBufferID.fileSize  = fileSize ;
    DBufferID.bufferSize    = bufferSize ;
    DBufferID.bufferIndex   = bufferIndex ;
    DBufferID.bufferFormat  = format ;
    DBufferID.bufferFreq    = freq ;


    NSLog(@"DBufferID initialised %@<%x>", DBufferID, &*DBufferID);
        //output of this is: "DBufferID initialised <DBuffer: 0x533a5f0><533a5f0>"

    NSLog(@"DBufferID.fileName initialised %@<%x>", DBufferID.fileName, &*DBufferID.fileName);
        //output of this is: "DBufferID.fileName initialised /Users/david/Library/Application Support/iPhone Simulator/4.2/Applications/7DA24283-8D58-49B8-BBEB-48B08D921367/OpenALRefine.app/b2.caf<55453a0>"

    NSLog(@"DBufferID.fileName retaincount %d", [DBufferID.fileName retainCount]);
        //output of this is: "DBufferID.fileName retaincount 3"

    AudioFileClose(fileID);

    return DBufferID;
}

Хорошо, пока все хорошо. В перо у меня есть простой интерфейс с кнопкой воспроизведения, прикрепленной к методу playStream. Я пытаюсь запустить тот же код в начале метода, например так:

- (NSUInteger)playStream:(NSString*)soundKey gain:(ALfloat)gain pitch:(ALfloat)pitch loops:(BOOL)loops
{
    NSLog(@"PlayStream activiated");

    ALenum err = alGetError(); // clear error code

    NSLog(@"soundLibrary retaincount %d", [soundLibrary retainCount]);

    DBuffer *retrieve = [soundLibrary objectForKey:@"101"];
    NSLog(@"retrieve initialised %@<%x>", retrieve, &*retrieve);
    NSLog(@"retrieve.fileName initialised %@<%x>", retrieve.fileName, &*retrieve.fileName);

Тем не менее, результаты от последнего к NSLogs:

"восстановить инициализированный <533a5f0>"

Пока все хорошо, тот же адрес памяти, который был отправлен в словарь. Однако при печати значение retrieve.fileName возвращает случайную строку, например, так:

"Инициализированный retrieve.fileName hu.lproj <55453a0>»

Вы заметите, что адрес памяти не изменился по сравнению с указанным в методе initializeStreamFromFile, напечатанном выше. Значение этой переменной выглядит случайным, другие значения, которые она возвратила:

» «/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/System/Library/PrivateFrameworks/WebKit.framework"

и т. Д. Или просто "EXC_BAD_ACCESS"

Я относительно новичок в цели C, но я предполагаю, что это явно связано с плохим управлением памятью. Я читал на Apple pdfs по управлению памятью, чтобы попытаться исправить, но безрезультатно. Любые идеи будут оценены.

Ответы [ 2 ]

2 голосов
/ 01 марта 2011

Существует ряд проблем с этим кодом, которые указывают на то, что было бы полезно перечитать Руководство по концепциям Objective-C (в частности, похоже, что у вас может быть немного опыта C ++ и делаем ли предположения, основанные на этом знании?). Я перечитываю этот конкретный документ раз в несколько месяцев в течение первых нескольких лет, когда я писал код Objective-C; очень полезно.

В частности:

  • &*retrieve.fileName фактически ничего не делает. Бросьте &*.

  • retainCount бесполезен. Счет сохранения объекта - это внутренняя деталь реализации. Относитесь к сохранению, считайте чисто как дельты; если вы увеличиваете его, вы должны уменьшить его, когда закончите с объектом.

  • (как сказал Николай) ваши переменные fileName и fileName2 переизданы, что может привести к сбою. И свойство fileName должно быть copy, а не retain. Руководство по управлению памятью хорошо обсуждает детали сохранения / освобождения.

Могу поспорить, что "построить и проанализировать" поймало бы большинство / все проблемы с сохранением релиза.

2 голосов
/ 01 марта 2011
  1. В loadFiles вы перевыпуск fileName и fileName2.
  2. свойство fileName должно быть объявлено copy вместо retain.
...