我正在使用ARC将Apple的SpeakHere示例中的AQRecorder类实现到我的项目中。为了让它编译,我不得不创建一个控制AQRecorder实例的类(AQRecorderController)(相当于示例中的SpeakHereController)。 AQRecorderController通过我的主视图控制器的笔尖连接,并作为属性实现。无论财产是强还是弱,都会出现问题。
我的问题是,在加载视图控制器后不久,AQRecorderController就会被释放,但只有在设备上进行测试时才会被释放。在模拟器中,这不会发生。它适用于iPad和iPhone,iOS 5和iOS 6.我需要在视图控制器的整个生命周期内维护此引用以进行录制(您无法在录制时删除录制器并希望有完成的文件)。
有没有人碰到这个或类似的东西?如果AQRecorderController属性很强,我在尝试使用它时会遇到错误的访问错误,如果它很弱,我只是得到一个nil,并且它无法使用。
非常感谢任何帮助。
formViewController.h:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@class AQRecorderController;
@interface formViewController : UIViewController <UIActionSheetDelegate, UITableViewDelegate, UIGestureRecognizerDelegate> {
IBOutlet AQRecorderController *aqRecorderController;
}
@property (nonatomic, weak) IBOutlet AQRecorderController *aqRecorderController;
@end
AQRecorderController.h
#import <Foundation/Foundation.h>
#import "AQRecorder.h"
@interface AQRecorderController : NSObject
{
AQRecorder *aqRecorder;
}
@property (readonly) AQRecorder* aqRecorder;
@property (nonatomic, assign) bool isRecording;
@property (nonatomic, strong) NSString* fileName;
-(bool)startRecording;
-(bool)pauseRecording;
-(bool)stopRecording;
-(bool)initializeRecordSettingsWithCompression:(bool)compressionEnabled;
@end
formView.xib: recorder nib http://i46.tinypic.com/v4qfrq.png
这是AQRecorderController发布后的堆栈跟踪:
2012-10-23 10:34:09.600 TestApp[510:907] (
0 TestApp 0x000f32ab
-[AQRecorderController dealloc] + 138
1 CoreFoundation 0x32247311 CFRelease + 100
2 CoreFoundation 0x3225195d <redacted> + 140
3 libobjc.A.dylib 0x31ad5489 <redacted> + 168
4 CoreFoundation 0x32249441 _CFAutoreleasePoolPop + 16
5 Foundation 0x37303a7f <redacted> + 466
6 CoreFoundation 0x322db5df <redacted> + 14
7 CoreFoundation 0x322db291 <redacted> + 272
8 CoreFoundation 0x322d9f01 <redacted> + 1232
9 CoreFoundation 0x3224cebd CFRunLoopRunSpecific + 356
10 CoreFoundation 0x3224cd49 CFRunLoopRunInMode + 104
11 GraphicsServices 0x32fb52eb GSEventRunModal + 74
12 UIKit 0x34e92301 UIApplicationMain + 1120
13 TestApp 0x00081a9d main + 48
14 TestApp 0x0005aa68 start + 40
)
这是录像机实例化的地方。
AQRecorderController.mm:
- (void)awakeFromNib
{
aqRecorder = new AQRecorder();
}
这是使用录音机的地方。到目前为止,AQRecorderController已经发布,并且此代码永远不会执行(它会导致崩溃,因为AQRecorderController已被解除分配)。
-(bool)startRecording
{
if (aqRecorder->IsRunning())
{
[self stopRecording];
}
else // If we're not recording, start.
{
@try
{
// Start the recorder
CFStringRef filenameString = (CFStringRef)CFBridgingRetain(self.fileName);
aqRecorder->StartRecord(filenameString);
}
@catch(NSException *ex)
{
NSLog(@"Error: %@", [ex description]);
return NO;
}
[self setFileDescriptionForFormat:aqRecorder->DataFormat() withName:@"Recorded File"];
}
[self checkIfRecording];
return YES;
}
这是实例化AQRecorderController的地方。
formViewController.mm:
//this is called in viewDidAppear
-(void)initializeAQRecorder: (NSString*)soundFileName
{
aqRecorderController = [[AQRecorderController alloc] init];
NSLog(@"AQRecorderController is being initialized for file %@",soundFileName);
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *soundFilePath =[[NSString alloc] initWithFormat:@"%@",[documentsDir stringByAppendingPathComponent:soundFileName]];
[aqRecorderController setFileName:soundFilePath];
[aqRecorderController initializeRecordSettingsWithCompression:NO];
}
答案 0 :(得分:3)
我的问题是加载视图控制器后不久, AQRecorderController已发布......我需要维护此参考 在我的视图控制器的整个生命周期中
标记您的媒体资源strong
而不是weak
。 weak
表示aqRecorderController
指向的对象不会被setter保留; strong
会导致它被保留。
如果AQRecorderController属性很强,我的访问权限很差 尝试使用它时出错,如果它很弱,我只是得到一个零,而且它无法使用。
听起来这个属性在你的程序中的某个地方被设置为某个无效值。由于您无法在ARC 和下手动保留对象,因此您已标记了属性weak
,因此可能很早就会将其释放。我不确定为什么如果你标记它strong
就会出现问题...它有助于查看设置变量或属性的代码。
答案 1 :(得分:1)
您永远不会从我看到的AQRecorderController
设置formViewController
。您需要执行self.aqRecorderController = aqRecorderController
,我相信只要您离开创建控制器的范围,它就会消失。
答案 2 :(得分:0)
我现在就开始工作了。我没有完全修复它,但我可以记录而不会崩溃。我注释掉了与AQRecorderController有关的每一行,直到它停止释放,然后慢慢地将它们添加回去,直到我发现它发生的地方。看起来音频会话设置代码以某种方式激发它释放控制器。这是导致它的代码(但这里没有抛出错误):
来自AQRecorderController.mm:
-(void)initializeRecordSettingsWithCompression:(bool)compressionEnabled
{
OSStatus error = AudioSessionInitialize(NULL, NULL, interruptionListener, (__bridge void*)self);
if (error) printf("ERROR INITIALIZING AUDIO SESSION! %d\n", (int)error);
else
{
UInt32 category = kAudioSessionCategory_PlayAndRecord;
error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
if (error) printf("couldn't set audio category!");
error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, (__bridge void*)self);
if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error);
UInt32 inputAvailable = 0;
UInt32 size = sizeof(inputAvailable);
// we do not want to allow recording if input is not available
error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable);
if (error) printf("ERROR GETTING INPUT AVAILABILITY! %d\n", (int)error);
// we also need to listen to see if input availability changes
error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, propListener, (__bridge void*)self);
if (error) printf("ERROR ADDING AUDIO SESSION PROP LISTENER! %d\n", (int)error);
error = AudioSessionSetActive(true);
if (error) printf("AudioSessionSetActive (true) failed");
}
}
到目前为止,这不是我的应用程序运行所必需的,但我很好奇为什么它会导致AQRecorderController实例发布。