Как лучше цеплять задачи, используя BoltsSwift?

При первом использовании Болтов я почти понимаю, как они работают, но я уверен, что должен быть более чистый способ делать то, что я делаю.

В моем примере я хочу загрузить JSON с категориями, импортировать их в Core Data, затем загрузить JSON с ингредиентами и импортировать их. В этом порядке должно произойти, так как мой парсер требует Category объекты существуют уже до разбора Ingredient объекты.

Я использую BoltsSwift, чтобы избежать вложенных блоков, поэтому я сделал так, чтобы мои "загрузчик" и "импортер" возвращали Task,

Сетевой вызов (с помощью Мойя):

static func downloadJSON(target: MoyaAPI) -> BoltsSwift.Task<JSONArray> {
    let taskCompletionSource = TaskCompletionSource<JSONArray>()
    requestJSONArray(target, success: { (jsonArray) in
        taskCompletionSource.set(result: jsonArray)
    }, error: { (error) in
        taskCompletionSource.set(error: error)
    }, failure: { (moyaError) in
        taskCompletionSource.set(error: moyaError)
    })
    return taskCompletionSource.task
}

Разбор части (с помощью Groot):

func importCategories(from json: JSONArray) -> BoltsSwift.Task<[Category]> {
    let taskCompletionSource = TaskCompletionSource<[Category]>()
    do {
        let categories: [Category] = try objects(fromJSONArray: json, inContext: managedObjectContext)
        taskCompletionSource.set(result: categories)
    } catch {
        taskCompletionSource.set(error: error)
    }
    return taskCompletionSource.task
}

Итак, позже, когда я попытаюсь объединить эти 4 задачи вместе, я придумал следующее:

    NetworkAdapter.downloadJSON(target: .categories).continueOnSuccessWithTask { (json) -> Task<[Category]> in
        return importer.importCategories(from: json)
    }.continueOnSuccessWith { (categories) in
        return NetworkAdapter.downloadJSON(target: .ingredients).continueOnSuccessWithTask(continuation: { (json) -> Task<[Ingredient]> in
            return importer.importIngredients(from: json)
        })
    }

Это работает, но у меня есть ощущение, что синтаксис может быть более читабельным. Может кто-нибудь объяснить, как правильно соединить эти 4 задачи?

1 ответ

Решение

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

NetworkAdapter.downloadJSON(target: .categories)
  .continueOnSuccessWithTask { (json) in
    return importer.importCategories(from: json)
  }
  .continueOnSuccessWithTask { (_) in
    return NetworkAdapter.downloadJSON(target: .ingredients)
  }
  .continueOnSuccessWithTask { (json) in
    return importer.importIngredients(from: json)
  }

(Если компилятор запутался, вам, возможно, придется заново добавить декларации возвращаемого типа внутри замыканий.)

Если вышеприведенное работает для вас, вы можете еще больше уменьшить свой код, используя встроенные замыкания:

NetworkAdapter.downloadJSON(target: .categories)
  .continueOnSuccessWithTask { importer.importCategories(from: $0) }
  .continueOnSuccessWith { NetworkAdapter.downloadJSON(target: .ingredients) }
  .continueOnSuccessWithTask { importer.importIngredients(from: $0) }
Другие вопросы по тегам