简体   繁体   English

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

[英]How to properly handle NSFileHandle exceptions in Swift 2.0?

First of all, I am new to iOS and Swift and come from a background of Android/Java programming. 首先,我是iOS和Swift的新手,来自Android / Java编程背景。 So to me the idea of catching an exception from an attempt to write to a file is second nature, in case of lack of space, file permissions problems, or whatever else can possibly happen to a file (and has happened, in my experience). 因此,对于我来说,尝试写入文件时捕获异常的想法是第二天性,如果缺少空间,文件权限问题或文件中可能发生的任何其他事情(根据我的经验,已发生) 。 I also understand that in Swift, exceptions are different from Android/Java ones, so that's not what I'm asking about here. 我也明白,在Swift中,异常与Android / Java不同,所以这不是我在这里要求的。

I am attempting to append to a file using NSFileHandle, like so: 我试图使用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!)
}

However, both the seekToEndOfFile() , and writeData() functions indicate that they throw some kind of exception: 但是, seekToEndOfFile()writeData()函数都表明它们会抛出某种异常:

This method raises an exception if the file descriptor is closed or is not valid, if the receiver represents an unconnected pipe or socket endpoint, if no free space is left on the file system, or if any other writing error occurs. 如果文件描述符已关闭或无效,如果接收器表示未连接的管道或套接字端点,文件系统上没有剩余空闲空间,或者发生任何其他写入错误,则此方法引发异常。 - Apple Documentation for writeData() - writeData() Apple文档

So what is the proper way to handle this in Swift 2.0? 那么在Swift 2.0中处理这个问题的正确方法是什么? I've read the links Error-Handling in Swift-Language , try-catch exceptions in Swift , NSFileHandle writeData: exception handling , Swift 2.0 exception handling , and How to catch an exception in Swift , but none of them have a direct answer to my question. 我已经阅读了Swift-Language中的错误处理链接,Swift中的 try-catch异常NSFileHandle writeData:异常处理Swift 2.0异常处理以及如何在Swift中捕获异常 ,但没有一个直接回答我的问题。 I did read something about using objective-C in Swift code, but since I am new to iOS, I don't know what this method is and can't seem to find it anywhere. 我确实读过一些关于在Swift代码中使用objective-C的东西,但由于我是iOS新手,我不知道这个方法是什么,似乎无法在任何地方找到它。 I also tried the new Swift 2.0 do-catch blocks, but they don't recognize that any type of error is being thrown for NSFileHandle methods, most likely since the function documentation has no throw keyword. 我也尝试了新的Swift 2.0 do-catch块,但他们没有意识到NSFileHandle方法会抛出任何类型的错误,很可能因为函数文档没有throw关键字。

I am aware that I could just let the app crash if it runs out of space or whatever, but since the app will possibly be released to the app store later, I don't want that. 我知道我可以让应用程序崩溃,如果它用完了空间或其他什么,但由于应用程序可能会在以后发布到应用商店,我不希望这样。 So how do I do this the Swift 2.0 way? 那么我如何以Swift 2.0的方式做到这一点呢?

EDIT: This currently is a project with only Swift code, so even though it seems there is a way to do this in Objective-C, I have no idea how to blend the two. 编辑:这个目前只是一个只有Swift代码的项目,所以即使看起来有一种方法可以在Objective-C中做到这一点,我也不知道如何将两者混合在一起。

a second (recoverable) solution would be to create a very simple ObjectiveC++ function that takes a block and returns an exception. 第二个(可恢复的)解决方案是创建一个非常简单的ObjectiveC ++函数,它接受一个块并返回一个异常。

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的文件,并在你的桥接头中添加它(如果你还没有,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;
}

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
}

This can be achieved without using Objective C code, here is a complete example. 可以在不使用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
    }
}

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

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". seekToEndOfFile()writeData()没有标记为throws (它们不会抛出一个可以用do-try-catch块捕获的NSError对象),这意味着在Swift的当前状态下, NSException由他们不能被“抓住”。

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. 如果您正在处理Swift项目,您可以创建一个Objective-C类来实现捕获NSExceptionNSFileHandle方法(就像在这个问题中一样 ),但是否则你运气不好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM