Как дождаться завершения функции на iOS / Swift, прежде чем начать вторую



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



Как мне настроить viewDidLoad, чтобы вторая функция выполнялась только один раз и мой запрос данных был выполнен успешно?



var searchLocation = String()
var searchLocationCoordinates = [String:Double]()
var searchRange = Int()


override func viewDidLoad() {
super.viewDidLoad()

// Gets the user's search preference
getTheSearchLocationAndRange()

// Loads the data from the database
loadDataFromDatabase()
}


Я читал материал до сих пор с dispatch_asynch или обработчиком завершения. Может быть, кто-то может опубликовать какой-то код, который я могу использовать в своем viewDidLoad и заставить его работать?

718   3  

3 ответов:

Вы можете использовать быстрые замыкания! Они созданы для этого.

Пожалуйста, обратитесь к руководству Apple: затворы

Вот код, который вам нужен в вашем конкретном случае.

FinishedDownload-это закрытие. При вызове функции getTheSearchLocationAndRange() ее код выполняется до тех пор, пока не появится строка completed(), которая ожидает завершения всех процессов функции. Как только процессы завершаются (например, загрузка), completed() вызывает закрытие, которое активирует код, определенный в getTheSearchLocationAndRange { () -> () in. Поэтому loadDataFromDatabase() вызывается только после того, как getTheSearchLocationAndRange() полностью завершил выполнение и данные присутствуют (не nil).

    var searchLocation = String()
    var searchLocationCoordinates = [String:Double]()
    var searchRange = Int()
    typealias FinishedDownload = () -> ()

    override func viewDidLoad() {
        super.viewDidLoad()

        getTheSearchLocationAndRange()
    }

    func getTheSearchLocationAndRange(completed: FinishedDownload) {

           // Code for searching Location Range HERE

           completed()
    }

    getTheSearchLocationAndRange { () -> () in
        loadDataFromDatabase()
    }

Надеюсь, это решило вашу проблему и ответило на ваш вопрос:)

Кстати, о части "оставить свой графический интерфейс висеть", Alamofire автоматически позаботится об этом для вас. Если вы не используете Alamofire, то вам придется вручную назначить асинхронный запрос фоновому потоку, чтобы ваш графический интерфейс не перестал отвечать.

Я написал демо-проект и разместил его на GitHub, который имитирует обработку асинхронной сетевой загрузки. Взгляните на DuncanMC/SwiftCompletionHandlers.

В частности, рассмотрим метод asyncFetchImage (), который делает почти точно то, о чем говорит этот поток: использует асинхронный метод внутри и принимает блок завершения, который он вызывает после выполнения асинхронной нагрузки. Это общая схема, которую вы должны использовать. Напишите метод, который принимает блок завершения / закрытие. Внутренне, пусть этот метод вызовет любую асинхронную функцию, которая ему нужна, а затем вызовет ваше завершение закрытия изнутри завершения вызова асинхронного метода.

Функция asyncFetchImage выглядит следующим образом:

func asyncFetchImage(imageName imageName: String,
  completion: (
    image: UIImage?,
    status: String) -> ())
{
  print("Entering \(#function)")

  //Simulate a network operation by waiting a few seconds before loading an image
  let nSecDispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(3.0 * Double(NSEC_PER_SEC)))
  let queue = dispatch_get_main_queue()
  dispatch_after(nSecDispatchTime, queue)
    {
      () -> Void in
      let result = UIImage(named: imageName)
      print("Loading image in background")
      let status = result != nil ? "image loaded" : "Error loading image"
      print("About to call completion handler")
      completion(image: result, status: status)
  }
  print("Leaving \(#function)")
}

Ладно я нашел решение. Я в основном вызвал функцию в конце первого.

Итак, в основном:

    var searchLocation = String()
    var searchLocationCoordinates = [String:Double]()
    var searchRange = Int()


    override func viewDidLoad() {
        super.viewDidLoad()

        // Gets the user's search preference
        getTheSearchLocationAndRange()
    }

    func getTheSearchLocationAndRange() {
    // Code for getTheSearchLocationAndRange()

    loadDataFromDatabase()
    }

    func loadDataFromDatabase(){
    // Code for loadDataFromDatabase()
    }

Comments

    Ничего не найдено.