如何正确处理Swift 2.0中的NSFileHandleexception?

首先,我是iOS和Swift的新手,来自Android / Java编程的背景。 所以对于我来说,从写入文件的尝试中捕获exception的想法是第二性质,在缺less空间,文件权限问题或任何其他可能发生的文件(并已发生,根据我的经验) 。 我也明白,在Swift中,exception是不同于Android / Java的,所以这不是我在这里问的。

我试图追加到使用NSFileHandle的文件,如下所示:

let fileHandle: NSFileHandle? = NSFileHandle(forUpdatingAtPath: filename) if fileHandle == nil { //print message showing failure } else { let fileString = "print me to file" let data = fileString.dataUsingEncoding(NSUTF8StringEncoding) fileHandle?.seekToEndOfFile() fileHandle?.writeData(data!) } 

然而, seekToEndOfFile()writeData()函数都表明它们抛出某种exception:

如果文件描述符closures或无效,接收方表示未连接的pipe道或套接字端点,文件系统上没有剩余空间,或者发生其他写入错误,则此方法引发exception。 – writeData() Apple文档

那么在Swift 2.0中处理这个问题的正确方法是什么呢? 我已经阅读了Swift-Language中的error handling,Swift中的 try-catchexception , NSFileHandle writeData:exception处理 , Swift 2.0exception处理 ,以及如何在Swift中捕获exception ,但没有一个直接回答我的问题。 我读了一些关于在Swift代码中使用Objective-C的内容,但是由于我是iOS新手,我不知道这个方法是什么,也不能在任何地方find它。 我也尝试了新的Swift 2.0 do-catch块,但是他们不知道NSFileHandle方法会抛出任何types的错误,很可能是因为函数文档没有throw关键字。

我知道,如果应用程序在空间不足或其他情况下崩溃,我可能会崩溃,但由于应用程序稍后可能会发布到应用程序商店,所以我不希望这样做。 那么我该如何做Swift 2.0呢?

编辑:目前这是一个只有Swift代码的项目,所以即使看起来有一种方法可以在Objective-C中做到这一点,我不知道如何融合两者。

第二个(可恢复的)解决scheme是创build一个非常简单的ObjectiveC ++函数,它接受一个块并返回一个exception。

创build一个名为ExceptionCatcher.h的文件,并将其添加到您的桥接头中(如果您还没有,Xcode会提示为您创build一个)

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

使用这个帮手很简单,我已经从上面调整了我的代码来使用它。

 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 } 

可以在不使用Objective C代码的情况下实现,这里是一个完整的例子。

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

调用SomeClass.appendString("add me to file", filename:"/some/file/path.txt")来运行它。

seekToEndOfFile()writeData()不会被标记为throws (它们不会抛出一个可以被do-try-catch块拦截的NSError对象),这意味着在当前的Swift状态下,他们不能被“抓住”。

如果你正在做一个Swift项目,你可以创build一个Objective-C类来实现你的NSFileHandle方法来捕获NSException (就像这个问题一样 ),但是否则你NSException幸运了。