自定义类中的NSString - >被添加到词典 - >获取时NSString值已更改?

时间:2011-03-01 11:56:02

标签: iphone streaming nsmutabledictionary openal

我正在尝试使用OpenAL在iphone上传输文件。大部分代码都基于excellent tutorial by Ben Britten;但是,我试图将数据存储在字典中的自定义类中,而不是字典中的字典中。

我已经设置了自定义类来保存有关我将要流式传输的文件的信息。这里包含一个名为fileName的NSString,它保存了我的文件的位置。正是这个变量在检索时改变了它的价值。自定义类定义如下:

@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实例方法从字典中检索文件名并且它工作正常,返回:

  

“retrieve:/ Users / david / Library / Application Support / iPhone   模拟器/ 4.2 /应用/ 7DA24283-8D58-49B8-BBEB-48B08D921367 / OpenALRefine.app / b2.caf“

哪个是正确的地址,与下面所示的初始化时日志的spat相同,并且

  

“检索retaincount: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);

但是,最后一个NSLog的结果是:

  

“检索已初始化&lt; 533a5f0&gt;”

到目前为止一直很好,与发送到字典的内存地址相同。但是,当我打印retrieve.fileName的值时返回一个随机字符串,如下所示:

  

“retrieve.fileName initialised hu.lproj&lt; 55453a0&gt;”

您会注意到内存地址与上面打印的initializeStreamFromFile方法中显示的内存地址没有任何变化。这个变量的值似乎是随机的,它返回的其他值是:

  

”   “/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/System/Library/PrivateFrameworks/WebKit.framework”

等......或者只是“EXC_BAD_ACCESS”

我在目标C上相对较新,但我猜它显然与糟糕的内存管理有关。我一直在阅读有关内存管理的苹果pdf,试图修复但无济于事。任何见解都将不胜感激。

2 个答案:

答案 0 :(得分:2)

  1. loadFiles fileName过度发送fileName2fileName
  2. copy属性应声明为retain而不是{{1}}。

答案 1 :(得分:2)

此代码存在许多问题,表明重新阅读Objective-C concepts guide会有所帮助(特别是,看起来您可能有一些C ++经验并且正在做出基于的假设那知识?)。在我编写Objective-C代码的最初几年里,我每隔几个月重读一次这个特定文档;非常有帮助。

特别是:

  • &*retrieve.fileName实际上什么也没做。放下&*

  • retainCount没用。对象的保留计数是内部实现细节。将保留计数纯粹视为增量;如果你使它增加,你必须在完成对象后减少它。

  • (正如Nikolai所说)你的fileNamefileName2变量被过度释放,可能导致崩溃。 fileName属性应为copy,而不是retainmemory management guide在讨论保留/发布细节方面做得很好。

我敢打赌,“构建和分析”会捕获大部分/全部保留释放问题。