SIGABRT: -[NSConcreteFileHandle seekToEndOfFile]: No such file or directory

1k Views Asked by At

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];
        }

}
1

There are 1 best solutions below

1
Zen On

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:

[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);
        NSFileHandle *myHandle;
        myHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
        [myHandle seekToEndOfFile];
        [myHandle writeData:[accelvalue dataUsingEncoding:NSUTF8StringEncoding]];
        [myHandle closeFile];
    }];