So I am writing accelerometer values to a csv file. Sometimes it works and sometimes it doesn't. Typically when the accelerometer is on for over 5 seconds it crashes and I get the error.
Here is the code:
int recordbuttonstatus=0;
int playbuttonstatus=0;
int count;
NSString *dataStr;
NSString *dirName;
NSFileManager *filemgr;
NSString *audiofilename = @"Pneumonia_audio.wav";
NSString *audiofilepath;
NSString *csvfileName = @"accel.csv";
NSFileHandle *myHandle;
- (void)viewDidLoad {
[super viewDidLoad];
playbuttonimage.enabled=FALSE;
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
audiofilename,
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
// Define the recorder setting
NSDictionary *recordSetting = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:AVAudioQualityMin],
AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],
AVEncoderBitRateKey,
[NSNumber numberWithInt: 1],
AVNumberOfChannelsKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
nil];
// Initiate and prepare the recorder
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)recordbuttonaction:(id)sender {
if (recordbuttonstatus==0){
[recordbuttonimage setImage:[UIImage imageNamed:@"stoprecord.png"] forState:UIControlStateNormal];
recordbuttonstatus=1;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
// Start recording
[recorder record];
//Prepare writing to csv
dirName = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
filePath = [dirName stringByAppendingPathComponent: csvfileName];
filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath:filePath]) {
NSLog(@"File %@ being overwritten...", csvfileName);
NSError *error = nil;
[filemgr removeItemAtPath:filePath error:&error];}
else {
NSLog(@"File %@ doesn't exist. Making %@.", csvfileName,csvfileName);
}
[[NSFileManager defaultManager] createFileAtPath:filePath
contents:nil
attributes:nil];
myHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
//Start accelerometer
count =0;
motionManager = [[CMMotionManager alloc] init];
motionManager.deviceMotionUpdateInterval=.02;
[motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *deviceMotion, NSError *error) {
CMAcceleration userAcceleration = deviceMotion.userAcceleration;
float accelval = userAcceleration.y*9.81;
count = count + 1;
NSString *accelvalue = [[NSString alloc] initWithFormat:@"%f\n",accelval];
NSLog(@"number: %d Accelval: %f",count, accelval);
[myHandle seekToEndOfFile];
[myHandle writeData:[accelvalue dataUsingEncoding:NSUTF8StringEncoding]];
}];
}
else{
[motionManager stopDeviceMotionUpdates];
[myHandle closeFile];
[recordbuttonimage setImage:[UIImage imageNamed:@"record.png"] forState:UIControlStateNormal];
recordbuttonstatus=0;
playbuttonimage.enabled=TRUE;
[playbuttonimage setImage:[UIImage imageNamed:@"play.png"] forState:UIControlStateNormal];
[recorder stop];
}
}
So I experimented with initiating and changing when I called [fileHandle closeFile] and I got it:
I needed to make sure that there was no chance that the fileHandle would change after a recording or that closeFile was called too early/too late. So I put all the fileHandle lines in the block in which the accelerometer would update for each value. It was afraid it would lag my code but it didn't.
Here is the code: