Можно ли выкинуть из класса init() в Swift с постоянной строкой, загруженной из файла?
Я хотел бы, чтобы мой класс init() в Swift выкинул ошибку, если что-то пошло не так, как при загрузке файла в строку внутри класса. Как только файл будет загружен, строка не будет изменена, поэтому я бы предпочел использовать let. Это работает:
class FileClass {
var text: NSString = ""
init() throws {
do {
text = try NSString( contentsOfFile: "/Users/me/file.txt", encoding: NSUTF8StringEncoding ) }
catch let error as NSError {
text = ""
throw error
}
}
}
но когда я заменяю
var text: NSString = ""
с
let text: NSString
Я получаю . Все хранимые свойства экземпляра класса должны быть инициализированы перед тем, как выбраться из ошибки инициализации.
Я пробовал различные подходы, например, чтобы сделать текст необязательным
let text: NSString?
но не нашли никакой работы. Возможно ли, чтобы текст был загружен из файла, неизменный, и для init(), чтобы выбросить ошибку? Могу ли я получить торт и съесть его три?
Большое спасибо заранее!
Ответы
Ответ 1
[Обновить] Swift Version >= 2.2
Так как Swift 2.2 вы можете нарушить выполнение инициализатора класса без необходимости заполнения всех сохраненных свойств
class FileStruct {
let text: String
init() throws {
do {
text = try String(contentsOfFile: "/Users/me/file.txt", encoding: NSUTF8StringEncoding ) }
catch let error as NSError {
throw error
}
}
}
Swift Version <= 2.1
В настоящее время в Swift class
вы не можете сломать выполнение инициализатора перед инициализацией каждого сохраненного свойства.
С другой стороны, у вас нет этого ограничения с structs
, поэтому
struct FileStruct {
var text: String
init() throws {
do {
text = try String(contentsOfFile: "/Users/me/file.txt", encoding: NSUTF8StringEncoding ) }
catch let error as NSError {
throw error
}
}
}
Вы также можете избежать блокировки do/catch
struct FileStruct {
var text: String
init() throws {
text = try String(contentsOfFile: "/Users/me/file.txt", encoding: NSUTF8StringEncoding)
}
}
Наконец, я заменил NSString
на String
, так как мы используем Swift, а не Objective-C; -)
Ответ 2
Вместо этого вы можете использовать отказоустойчивый инициализатор, как это более подходит для такого рода сценариев.
class FileClass {
let text: String
init?() {
guard let fileContents = try? NSString( contentsOfFile: "/Users/me/file.txt", encoding: NSUTF8StringEncoding ) else {
text = ""
return nil
}
text = fileContents as String
}
}
или, если вы хотите напечатать ошибку:
class FileClass {
let text: String
init?() {
do {
text = try String( contentsOfFile: "/Users/me/file.txt", encoding: NSUTF8StringEncoding )
} catch let error as NSError {
print("Error while reading: \(error)")
text = ""
return nil
}
}
}
Использование проще, чем с инициализатором throwing, поскольку вы можете использовать if-let
или guard-let
:
if let file = FileClass() {
}
или
guard let file = FileClass() else {
return
}
против
let file: FileClass
do {
file = FileClass()
} catch {
}