First of all, I am new to iOS and Swift and come from a background of Android/Java programming. So to me the idea of catching an exception from an attempt to write to a file
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
}
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 NSException
s 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 NSException
s (like in this question), but otherwise you're out of luck.
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.