Быстрый запуск запуска только при получении данных - PullRequest
1 голос
/ 13 февраля 2020

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

static func wordDefin (word : String, completion: @escaping (_ def: String )->(String)) {
        let wordEncoded = word.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        let uri = URL(string:"https://dictapi.lexicala.com/search?source=global&language=he&morph=false&text=" + wordEncoded! )
        if let unwrappedURL = uri {
            var request = URLRequest(url: unwrappedURL);request.addValue("Basic bmV0YXlhbWluOk5ldGF5YW1pbjg5Kg==", forHTTPHeaderField: "Authorization")
            let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
                do {
                if let data = data {
                    let decoder = JSONDecoder()
                    let empty = try decoder.decode(Empty.self, from: data)
                    if (empty.results?.isEmpty)!{
                        print("oops looks like the word :" + word)
                        game.wordsList.removeAll(where: { ($0) == game.word })
                        game.floffWords.removeAll(where: { ($0) == game.word })
                        helper.newGame()
                    } else {
                        let definition =  empty.results?[0].senses?[0].definition
                        _ = completion(definition ?? "test")
                        return
                    }
                    }
                }
                catch {
                    print("connection")
                    print(error)
                }
        }
            dataTask.resume()
        }
    }

1 Ответ

1 голос
/ 13 февраля 2020

Вы не можете остановить контроллер представления от «запуска» самого себя (за исключением того, чтобы вообще не нажимать / представлять / показывать его). Как только вы нажимаете / представляете / показываете его, его жизненный цикл не может и не должен быть остановлен. Поэтому вы несете ответственность за загрузку соответствующего пользовательского интерфейса для «состояния загрузки», который может быть контроллером с пустым представлением с загрузчиком. Вы можете сделать это как хотите, включая загрузку полного пользовательского интерфейса с .isHidden = true, установленным для всех объектов просмотра. Идея состоит в том, чтобы сделать как можно больше предварительной загрузки пользовательского интерфейса, пока база данных работает в фоновом режиме, чтобы, когда данные были готовы, вы могли отобразить полный пользовательский интерфейс с наименьшим количеством работы.

Я рекомендую после того, как вы загрузили пользовательский интерфейс в его «загрузочной» конфигурации, загрузите данные как последний шаг в вашем потоке и используйте обработчик завершения, чтобы завершить sh задачу:

override func viewDidLoad() {
    super.viewDidLoad()

    loadData { (result) in
        // load full UI
    }

}

Ваш метод данных может выглядеть примерно так:

private func loadData(completion: @escaping (_ result: Result) -> Void) {
    ...
}

РЕДАКТИРОВАТЬ

Рассмотрите возможность создания менеджера данных, который работает по следующим направлениям. Поскольку менеджер данных является классом (ссылочным типом), при передаче его другим контроллерам представления все они указывают на один и тот же экземпляр менеджера. Следовательно, изменения, которые любой из контроллеров представления вносит в него, видны другими контроллерами представления. Это означает, что когда вы используете sh новый контроллер представления и пора обновить метку, получите доступ к ней из свойства data. А если он не готов, подождите, пока менеджер данных не уведомит контроллер представления о готовности.

class GameDataManager {

    // stores game properties
    // updates game properties
    // does all thing game data

    var score = 0
    var word: String?

}

class MainViewController: UIViewController {

    let data = GameDataManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        // when you push to another view controller, point it to the data manager
        let someVC = SomeOtherViewController()
        someVC.data = data

    }

}

class SomeOtherViewController: UIViewController {

    var data: GameDataManager?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let word = data?.word {
            print(word)
        }

    }

}

class AnyViewController: UIViewController {

    var data: GameDataManager?

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...