Как правильно обрабатывать исключения NSFileHandle в Swift 2.0?
Прежде всего, я новичок в 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? Я прочитал ссылки
Обработка ошибок в Swift-Language, исключения try-catch в Swift, NSFileHandle writeData: обработка исключений, Обработка исключений Swift 2.0 и Как поймать исключение в Swift, но ни один из них не имеет прямого ответа на мой вопрос. Я прочитал что-то об использовании objective-C в Swift-коде, но поскольку я новичок в iOS, я не знаю, что этот метод и не может найти его где-нибудь. Я также попробовал новые Swift 2.0 do-catch
, но они не признают, что для методов NSFileHandle генерируется какой-либо тип ошибки, скорее всего, поскольку в документации по функциям нет ключевого слова throw.
Я знаю, что я мог просто позволить краху приложения, если у него закончилось свободное пространство или что-то еще, но поскольку приложение, возможно, позже будет выпущено в магазин приложений, я этого не хочу. Итак, как мне это сделать Swift 2.0?
EDIT: В настоящее время это проект с только кодом Swift, поэтому, хотя кажется, что есть способ сделать это в Objective-C, я понятия не имею, как смешать эти два.
Ответы
Ответ 1
вторым (восстанавливаемым) решением было бы создание очень простой функции ObjectiveС++, которая берет блок и возвращает исключение.
создайте файл под названием: 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
}
Ответ 2
seekToEndOfFile()
и writeData()
не помечены как throws
(они не бросают объект NSError
, который может быть захвачен блоком do-try-catch
), что означает в текущем состоянии Swift, созданный ими NSException
не может быть "пойман".
Если вы работаете над проектом Swift, вы можете создать класс Objective-C, который реализует ваши методы NSFileHandle
, которые ловит NSException
(например, этот вопрос), но в противном случае вам не повезло.
Ответ 3
Это может быть достигнуто без использования кода 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")
, чтобы запустить его.