Обработчик быстрого завершения - избегание конечного закрытия

Я прочитал довольно много статей о быстрых функциях с замыканиями, замыкающими замыканиями и функциями экранирования. Кажется, все они приводят примеры, которые достаточно разные, и я не понимаю, что я делаю не так со своей собственной функцией.

Моя основная проблема заключается в том, как выполнить функцию конечного закрытия.

Я создал эту функцию для загрузки изображения в firebase. Он принимает два входа и должен возвращать строку (imageURL). Я верю, что с этой функцией все в порядке.

func uploadImageToFirebaseAndReturnImageURL(directory: String, image: UIImage!, handler: @escaping(_ imageURL: (ImageURL))  -> ()) {
    let imageName = NSUUID().uuidString // create unique image name

    if let uploadData = UIImagePNGRepresentation(image) {
        DB_STORE.child(directory).putData(uploadData, metadata: nil, completion: { (metadata, error) in

            if error != nil {
                print(error)
                return
            }

            if let profileImageUrl = metadata?.downloadURL()?.absoluteString {
                let d = ImageURL(imageURL: profileImageUrl)
                handler (d)             
            }
            return

        })
    }
}

Моя проблема в том, как правильно выполнить эту функцию, когда дело касается обработчика. Я хочу сначала выполнить функцию, а затем по завершении я хочу получить imageURL и использовать эту переменную в другой вложенной функции, которая загружает эту переменную (String) в базу данных firebase.

uploadImageToFirebaseAndReturnImageURL(directory: "profileImage", image: selectedImageFromPicker!, handler: { imageURL in
    guard let uid = Auth.auth().currentUser.uid else { print("User is not logged in"); return }
    DataService.instance.updateUserWithProfileImageURL(uid: uid, imageURL: imageURL)
    print("")
}

Что я делаю неправильно?


person Chris_1983_Norway    schedule 20.10.2017    source источник


Ответы (1)


Чтобы передать завершающее закрытие необходимо завершить / закрыть вызов функции и опустить метку аргумента закрытия. Например:

func foo(first: Int, second: Int, handler: (Int) -> Void) {
    ...
}

синтаксис вызова:

foo(first: 10, second: 20) { result in
    /* trailing closure body */
}

Кстати, вы должны просто объявить handler аргумент из:

handler: @escaping (_ imageURL: (ImageURL)) -> ()

к этому:

handler: @escaping (ImageURL) -> Void

Использование Void или () - вопрос стиля, поскольку они логически одинаковы. Я предпочитаю первое;)

person Paulo Mattos    schedule 20.10.2017
comment
Означает ли Void только любой тип данных? Так может быть строка? - person Chris_1983_Norway; 21.10.2017
comment
Нет, это будет Any. Тип Void - это просто псевдоним пустого кортежа, то есть (). - person Paulo Mattos; 21.10.2017