Swift 2: невозможно вызвать createDirectoryAtUrl с определением

В настоящее время я разрабатываю приложение на xCode7 beta 2 с использованием Swift 2 (на данный момент это требование).

Вот что я пытаюсь вызвать:

let fileManager = NSFileManager.defaultManager()
let tempDirectoryURL = NSURL(string: NSTemporaryDirectory())!
let directoryURL = tempDirectoryURL.URLByAppendingPathComponent("com.test.manager/multipart.form.data")
var error: NSError?

if fileManager.createDirectoryAtURL(directoryURL, createIntermediates: true, attributes: nil) {
 ...
}

Вот ошибка, которую я получаю:

Не удается вызвать «createDirectoryAtURL» со списком аргументов типа «(NSURL, createIntermediates: Bool, атрибуты: nil)»

Это сбивает с толку, потому что определение для createDirectoryAtURL, которое я получаю, когда щелкаю правой кнопкой мыши и «просматриваю определение»:

 func createDirectoryAtURL(
    url: NSURL, 
    withIntermediateDirectories createIntermediates: Bool, 
    attributes: [String : AnyObject]?
 ) throws

Единственный параметр, который не соответствует дословно, — это последний параметр «атрибуты», который в документации (и во всех примерах использования) явно указывается, может принимать значение nil.

Документация Apple:

Если вы укажете nil для этого параметра, каталог будет создан в соответствии со страницей umask(2) Mac OS X Developer Tools Manual процесса.


person Daymon Schroeder    schedule 01.07.2015    source источник


Ответы (1)


Здесь две проблемы:

  1. Вы изменили метку параметра на его внутреннее имя. Метка второго параметра — часть имени функции, необходимая для ее вызова — withIntermediateDirectories. Разработчик этой функции обращается к значению этого параметра как createIntermediates. Таким образом, ваш вызов должен выглядеть так:

    fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil)
    
  2. Обратите внимание на процитированную вами подпись:

    func createDirectoryAtURL( ... ) throws
    

    Вы используете этот вызов как условие оператора if — это означает, что вам нужна функция, которая возвращает Bool. Компилятор пытается удовлетворить требование оператора if, ища функцию с именем createDirectoryAtURL, чья сигнатура типа (NSURL, Bool, [String : AnyObject]?) -> Bool, и жалуется, потому что видит только ту, чья сигнатура (NSURL, Bool, [String : AnyObject]?) throws -> Void.

Система обработки ошибок в Swift 2 берет методы ObjC, которые возвращают BOOL и имеют выходной параметр NSError, и превращает их в методы throwing без возвращаемого типа (то есть они возвращают Void). Итак, если вы смотрите на код Swift 1.x, который использует такие методы, или портируете код ObjC, вам нужно изменить шаблоны, подобные следующим:

var error: NSError? 
if fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil, error: &error) {
    // all good
} else {
    // handle error
}

Вместо этого используйте такие шаблоны:

do {
    try fileManager.createDirectoryAtURL(directoryURL, withIntermediateDirectories: true, attributes: nil)
    // if here, all is good
} catch {
    // handle error
}
person rickster    schedule 01.07.2015
comment
Ах, спасибо! Это имеет большой смысл. Приступая к работе со Swift2, возникает множество странных преобразований (не обязательно сложных, просто запутанных). Как вы думаете, имело бы смысл, если бы они выдавали ошибку в немного отличающемся формате, например: 'functionName(params)->type expected'. - person Daymon Schroeder; 01.07.2015
comment
Диагностика компилятора определенно может быть улучшена. Сообщать об ошибках! - person rickster; 02.07.2015
comment
Подано. Спасибо за рекомендацию. - person Daymon Schroeder; 02.07.2015