如何正确处理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
幸运了。