How to properly handle NSFileHandle exceptions in Swift 2.0? How to properly handle NSFileHandle exceptions in Swift 2.0? ios ios

How to properly handle NSFileHandle exceptions in Swift 2.0?


a second (recoverable) solution would be to create a very simple ObjectiveC++ function that takes a block and returns an exception.

create a file entitled: ExceptionCatcher.h and add import it in your bridging header (Xcode will prompt to create one for you if you don't have one already)

////  ExceptionCatcher.h//#import <Foundation/Foundation.h>NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {    @try {        tryBlock();    }    @catch (NSException *exception) {        return exception;    }    return nil;}

Using this helper is quite simple, I have adapted my code from above to use it.

func appendString(string: String, filename: String) -> Bool {    guard let fileHandle = NSFileHandle(forUpdatingAtPath: filename) else { return false }    guard let data = string.dataUsingEncoding(NSUTF8StringEncoding) else { return false }    // will cause seekToEndOfFile to throw an excpetion    fileHandle.closeFile()    let exception = tryBlock {        fileHandle.seekToEndOfFile()        fileHandle.writeData(data)    }    print("exception: \(exception)")    return exception == nil}


This can be achieved without using Objective C code, here is a complete example.

class SomeClass: NSObject {    static func appendString(string: String, filename: String) -> Bool {        guard let fileHandle = NSFileHandle(forUpdatingAtPath: filename) else { return false }        guard let data = string.dataUsingEncoding(NSUTF8StringEncoding) else { return false }        // will cause seekToEndOfFile to throw an excpetion        fileHandle.closeFile()        SomeClass.startHandlingExceptions()        fileHandle.seekToEndOfFile()        fileHandle.writeData(data)        SomeClass.stopHandlingExceptions()        return true    }    static var existingHandler: (@convention(c) NSException -> Void)?    static func startHandlingExceptions() {        SomeClass.existingHandler = NSGetUncaughtExceptionHandler()        NSSetUncaughtExceptionHandler({ exception in            print("exception: \(exception))")            SomeClass.existingHandler?(exception)        })    }    static func stopHandlingExceptions() {        NSSetUncaughtExceptionHandler(SomeClass.existingHandler)        SomeClass.existingHandler = nil    }}

Call SomeClass.appendString("add me to file", filename:"/some/file/path.txt") to run it.


seekToEndOfFile() and writeData() are not marked as throws (they don't throw an NSError object which can be caught in with a do-try-catch block), which means in the current state of Swift, the NSExceptions raised by them cannot be "caught".

If you're working on a Swift project, you could create an Objective-C class which implements your NSFileHandle methods that catches the NSExceptions (like in this question), but otherwise you're out of luck.