首先,我是iOS和Swift的新手,来自Android / Java编程背景。因此,对于我来说,尝试写入文件时捕获异常的想法是第二天性,如果缺少空间,文件权限问题或文件中可能发生的任何其他事情(根据我的经验,已发生) 。我也明白,在Swift中,异常与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()
函数都表明它们会抛出某种异常:
如果文件描述符已关闭或无效,如果接收方表示未连接的管道或套接字端点,文件系统上没有剩余空间,或者发生任何其他写入错误,则此方法引发异常。 -
的Apple文档writeData()
那么在Swift 2.0中处理这个问题的正确方法是什么?我已经阅读了这些链接
Error-Handling in Swift-Language,try-catch exceptions in Swift,NSFileHandle writeData: exception handling,Swift 2.0 exception handling和How to catch an exception in Swift,但他们都没有直接回答我的问题。我确实读过一些关于在Swift代码中使用objective-C的内容,但由于我是iOS新手,我不知道这种方法是什么,似乎无法在任何地方找到它。我还尝试了新的Swift 2.0 do-catch
块,但是他们没有意识到NSFileHandle方法会抛出任何类型的错误,很可能因为函数文档没有throw关键字。
我知道我可以让应用程序崩溃,如果它的空间不足或其他什么,但由于应用程序可能会在以后发布到应用商店,我不想要那样。那么我如何以Swift 2.0的方式做到这一点?
编辑:这个目前只是一个只有Swift代码的项目,所以即使看起来有一种方法可以在Objective-C中实现这一点,我也不知道如何将它们混合在一起。 / p>
答案 0 :(得分:22)
第二个(可恢复的)解决方案是创建一个非常简单的ObjectiveC ++函数,该函数接受一个块并返回异常。
创建一个名为ExceptionCatcher.h的文件,并在你的桥接头中添加导入(如果你还没有,Xcode会提示为你创建一个)
//
// 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
}
答案 1 :(得分:1)
seekToEndOfFile()
和writeData()
未标记为throws
(他们不会抛出一个NSError
对象,可以使用do-try-catch
block),这意味着在Swift的当前状态下,由它们引发的NSException
不能被捕获&#34;。
如果您正在使用Swift项目,则可以创建一个Objective-C类,该类实现捕获NSFileHandle
的{{1}}方法(如this question中所示) ,但除此之外,你运气不好。
答案 2 :(得分:1)
这个可以在不使用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")
运行它。