如何在Swift 2.0中正确处理NSFileHandle异常?

时间:2016-01-22 21:09:53

标签: ios swift swift2 nsexception nsfilehandle

首先,我是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()函数都表明它们会抛出某种异常:

  

如果文件描述符已关闭或无效,如果接收方表示未连接的管道或套接字端点,文件系统上没有剩余空间,或者发生任何其他写入错误,则此方法引发异常。 - writeData()

的Apple文档

那么在Swift 2.0中处理这个问题的正确方法是什么?我已经阅读了这些链接 Error-Handling in Swift-Languagetry-catch exceptions in SwiftNSFileHandle writeData: exception handlingSwift 2.0 exception handlingHow to catch an exception in Swift,但他们都没有直接回答我的问题。我确实读过一些关于在Swift代码中使用objective-C的内容,但由于我是iOS新手,我不知道这种方法是什么,似乎无法在任何地方找到它。我还尝试了新的Swift 2.0 do-catch块,但是他们没有意识到NSFileHandle方法会抛出任何类型的错误,很可能因为函数文档没有throw关键字。

我知道我可以让应用程序崩溃,如果它的空间不足或其他什么,但由于应用程序可能会在以后发布到应用商店,我不想要那样。那么我如何以Swift 2.0的方式做到这一点?

编辑:这个目前只是一个只有Swift代码的项目,所以即使看起来有一种方法可以在Objective-C中实现这一点,我也不知道如何将它们混合在一起。 / p>

3 个答案:

答案 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")运行它。