Клоужеры, потоки и основы программирования

json
swift

#1

Всем привет!
Столкнулся с проблемой, подозреваю что это не столько swift, сколько основы программирования, но все же. Суть проблемы:
При использовании клоужеров или других вариантов, когда используется асинхронный поток, как понять, что дело сделано и можно пользоваться данными? Возможно, я просто мыслю линейно, а нужно по другому :slightly_smiling_face:

Пример 1: запрос данных с сервера. У меня получается сейчас забирать данные, парсить JSON и отображать результаты в таблице. Но вот если мне нужно получит данные для авторизации и до получения в приложении не должно ничего происходить, максиму повести прелоадер, что бы было видно что-то то происходит, как этого добиться?

Пример 2: Мне нужно получить фотки из галереи и отправит на сервер, я её открываю вот так:

@IBAction func photoButtonPressed(_ sender: Any) {
        let imagePickerController = UIImagePickerController()
        imagePickerController.delegate = self
        imagePickerController.sourceType = .photoLibrary
        present(imagePickerController, animated: true, completion: nil)
    }

и плюс расширение:

extension SignUpViewController: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        
        picker.dismiss(animated: true, completion: nil)
        guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
        photoImageView.image = image
    }
}

в момент вызова
present(imagePickerController, animated: true, completion: nil)
я так понимаю запускается асинхронный поток и код продолжает выполняться дальше. Как же понять что фото из галереи получено и можно его оправлять на сервер?


#2

С 1 пунктом я не совсем вас понимаю. У меня сложилось впечатление, что вы предполагаете всю работу в одном скрине. Тут скорее больше зависит от правильной архитектуры приложения, как правильно логически разделены части приложения на гостя и юзера.
Если я не так понял и все дело лишь в завершении запроса, то у вас уже все сделано. В момент когда парсите JSON это уже success. Перед началом запроса показываете лоадер, когда получили данные убираете его.

Для 2 пунтка у вас уже есть метод imagePickerController(_:didFinishPickingMediaWithInfo)
Тут вы и получаете выбранную картинку. Вы ее как раз ставите в imageView. Соответственно там же делаете остальную работу по запуску метода отправки на сервер.

Пример авторизации из вашего репозитория

 @IBAction func loginButtonPressed(_ sender: Any) {
        // show loader
        Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!) { (result, error) in
            if error != nil {
                // error
                print("Ошибка логин пароль")
            } else {
                print("Jump to the next screen")
            }
            // hide loader
        }
    }

#3

Спасибо, со вторым пунктом всё понятно.
А вот с авторизацией не очень.
Вот к примеру, я хочу получит uid пользователя:

func authAnonim() -> String {
        let uid = ""
        
        Auth.auth().signInAnonymously() { (authResult, error) in
            guard authResult != nil else {
                print("Результата авторизации нет!")
                return
            }
            print("Результат авторизации: \(authResult!)")
            DispatchQueue.main.async {
                guard let user = authResult?.user else { return }
                let isAnonymous = user.isAnonymous  // true
                let uid = user.uid
                print("Результат авторизации 2: \(uid)")
            }
        }
        print("Конец функции и uid = \(uid)")
        return uid
    }

Тут у меня слабые попытки вернуть значение uid :slight_smile:
Внутри замыкания всё прекрасно, но никак не пойму, как вернуть значение, нельзя же работать только внутри замыкания.


#4

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

func someFunc(closure: @escaping () -> (String)) {
    Auth.auth()... { ... in
        ...
        closure(uid)
    }
}

Использование

@IBAction func buttonTapped() {
    someFunc() { uid in
        // делаете дальнейшие действия с полученными данными
    }
}

Либо еще проще, просто создайте новый метод, который будет принимать данные и что-то делать дальше, и уже этот метод вызывайте в конце замыкания, когда получили свой uid.

func someFunc(closure: @escaping () -> (String)) {
        Auth.auth()... { ... in
            ...
            anotherFunc(uid)
        }
    }

@IBAction func buttonTapped() {
        someFunc()
    }

func anotherFunc(_ uid: String) {
    // to do
}

#5

Спасибо, вроде понял направление как нужно делать.