Swift Closures и порядок исполнения - PullRequest
0 голосов
/ 19 декабря 2018

Я изо всех сил пытаюсь создать приложение для своих собственных учебных целей, используя Swift.

Сейчас у меня следующий (желательный) порядок выполнения:

  1. TabView
  2. FirstViewController - TableView
  3. Проверка в CoreData
    • Если данные существуют, обновите массив с помощью замыкания
    • Если данных не существует, загрузите ихиспользуя Alamofire из API и сохраняя его в Core Data
  4. SecondViewController - CollectionView
    • Проверяет, существуют ли данные изображений в Core Data, если это так, загружает их оттуда,в противном случае загрузите его.

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

Например:

FirstViewController

var response: [DDGCharacter]
//coreData is an instance of such class
coreData.load(onFinish: { response in //Custom method in another class
    print("Finished loading")
    self.response = response
})

print("Executed after loading data from Core Data")
//If no data is saved, download from API
if response.count == 0 {
    //Download from API
}

Я провел вышеуказанный тест с тем же результатомв 10 руns получение:

Finished loading
Executed after loading data from Core Data

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

Так что мойвопрос в том, будет ли он выполняться в таком порядке всегда независимо от объема данных?Или это может измениться?Я также выполнил некоторую отладку, и они оба выполняются в основном потоке.Я просто хочу быть уверен, что мои предположения верны.

Как и просили в комментариях, вот реализация, выполненная в методе load():

func load(onFinish: ([DDGCharacter]) -> ()) {
    var characters: [DDGCharacter] = []

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
        return
    }

    let managedContext = appDelegate.persistentContainer.viewContext

    let fetchRequest = NSFetchRequest<NSManagedObject> (entityName: "DDGCharacter")

    do {
        characters = try managedContext.fetch(fetchRequest) as! [DDGCharacter]
    } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
    }

    onFinish(characters)
}

1 Ответ

0 голосов
/ 19 декабря 2018

Ваша реализация load(onFinish:) очень удивительна и слишком сложна.К счастью, это помогает продемонстрировать то, о чем вы спрашивали.

Закрытие выполняется, когда что-то вызывает его.Так что в вашем случае onFinish вызывается в конце метода, что делает его синхронным.Ничто в том, чтобы быть «замыканием», не делает ничего асинхронным.Это так же, как вызов функции.Совершенно нормально вызывать замыкание несколько раз (например, map).Или это никогда не может называться.Или это может быть вызвано асинхронно.По сути, это все равно, что передать функцию.

Когда я говорю «это немного отличается от анонимной функции», я просто имею в виду «закрыть» часть «закрытия».Закрытие «закрывает» текущую среду.Это означает, что он захватывает переменные в локальной области видимости, на которые ссылаются внутри замыкания.Это немного отличается от функции (хотя это больше о синтаксисе, чем о чем-то действительно глубоком; в некоторых случаях функции могут фактически стать замыканиями).

В этом случае лучшая реализация просто вернет массив.

...