iosobjective-cthread-safetynsfilehandle

How to make NSFilehandle to delete and write data concurrently in Objective c


I have written 2 methods:

  1. WriteToLogFile

  2. DeleteLogFile

and I am using NSFileHandle for this

My Code is written as:

- (void)WriteToLogFile:(NSString *)string {

 dispatch_async(logQueue ,^ {
        if (nil == fileHandle) {
            // log file not opened
            NSLog(@"LogFile not opened");
            return;
        }
        [fileHandle seekToEndOfFile];
        [fileHandle writeData:[string dataUsingEncoding:NSUTF8StringEncoding]];
      });
    }

And other function to delete as:

-(void) deleteLogDataFromFile
{
    NSString *logFilePath = [self getLogFilePath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if([fileManager fileExistsAtPath:logFilePath])
    {
    [[NSFileManager defaultManager] createFileAtPath:logFilePath contents:[NSData data] attributes:nil];
    fileHandle = [NSFileHandle fileHandleForWritingAtPath:logFilePath];
    }
}

Now I am calling these 2 methods from a loop to check if it crashes at some point where it fileHandle will try to Write to file and will found no such file exist

for (int i = 0; i<1000; i++) {
    [self WriteToLogFile:@"Hello"];
    [self DeleteLogs];
}

And Xcode throws me error b/w loop is running

Terminating app due to uncaught exception 'NSFileHandleOperationException', reason: '*** -[NSConcreteFileHandle writeData:]: Bad file descriptor'

So I need to know how should I make my Write to file Or Delete to file work together , I know I should do some locking on fileHandle. Can anyone tell what should be done in order to fix this issue?


Solution

  • A simple dispatch_async(logQueue ,^ {...}); in deleteLogDataFromFile method should do the trick. (assuming logQueue s a serial dispatch queue).

    For additional safety, consider making fileHandle a property in the class. Then override the getter, use

    @ synchronized(_fileHandle){
        return _fileHandle
    }
    

    And finally, use self.fileHandle in WriteToLogFile method.