我正在尝试使用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,试图修复但无济于事。任何见解都将不胜感激。
答案 0 :(得分:2)
loadFiles
fileName
过度发送fileName2
和fileName
。copy
属性应声明为retain
而不是{{1}}。答案 1 :(得分:2)
此代码存在许多问题,表明重新阅读Objective-C concepts guide会有所帮助(特别是,看起来您可能有一些C ++经验并且正在做出基于的假设那知识?)。在我编写Objective-C代码的最初几年里,我每隔几个月重读一次这个特定文档;非常有帮助。
特别是:
&*retrieve.fileName
实际上什么也没做。放下&*
。
retainCount
没用。对象的保留计数是内部实现细节。将保留计数纯粹视为增量;如果你使它增加,你必须在完成对象后减少它。
(正如Nikolai所说)你的fileName
和fileName2
变量被过度释放,可能导致崩溃。 fileName
属性应为copy
,而不是retain
。 memory management guide在讨论保留/发布细节方面做得很好。
我敢打赌,“构建和分析”会捕获大部分/全部保留释放问题。