Несколько асинхронных API для заполнения uitableview в нужном порядке iOS swift

У меня есть несколько вызовов API, которые будут обновлять uitableview всякий раз, когда они получают результаты. Пользовательский интерфейс необходимо обновлять по мере того, как API предоставляет данные. Все вызовы API являются асинхронными. Данные должны быть заполнены в правильном порядке. API0 должен обновить раздел 0, API1 должен обновить раздел 1 и так далее.

Мне удалось добиться этого с помощью двух API, но когда я использую третий API, у меня возникают сбои.

Пожалуйста, найдите мой код ниже:

    @IBOutlet weak var myTableView: UITableView!
var myDataSource: myTableDataSource!
var initialLoad = true
var tablD = [Int : [Any]]()
let queue = DispatchQueue(
    label: "com.affluvar.multipleAPI.MyQueue", // 1
    attributes: .concurrent)

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    myTableView.tableFooterView = UIView()
    API0()
    API1()
    API2()
}

//MARK: API methods
func API0(){
    queue.async {
        print("queue THREAD0????")
        getData(offset: 0,limit: 10){
            (finalArray) in
            print("IN FIRST????")
            for rest in finalArray{
                print(rest.name)
            }
            self.queue.sync {
                self.tablD.updateValue(finalArray, forKey: 0)
                self.myDataSource = myTableDataSource(data: self.tablD)
                print("SYNC DATASOURCE UPDATED 0????")
                DispatchQueue.main.async {
                    if self.initialLoad == true{
                        self.initialLoad = false
                        self.myTableView.dataSource = self.myDataSource
                        print("TABLE RELOADING INITIAL ????")
                        self.myTableView.reloadData()
                    }
                }
                self.saveData(data: finalArray, section: 0)
            }
        }

    }
}

func API1(){
    queue.async{
        print("queue THREAD1 ????")
        getData(offset: 10,limit: 12){
            (finalArray1) in
            print("IN SECOND ????")
            for rest in finalArray1{
                print(rest.name)
            }
            self.queue.sync{
                self.tablD.updateValue(finalArray1, forKey: 1)
                self.myDataSource = myTableDataSource(data: self.tablD)
                print("SYNC DATASOURCE UPDATED 1????")
                DispatchQueue.main.async {
                    if self.initialLoad == true{
                        self.initialLoad = false
                        self.myTableView.dataSource = self.myDataSource
                        print("TABLE RELOADING INITIAL ????")
                        self.myTableView.reloadData()
                    }
                }
                self.saveData(data: finalArray1, section: 1)
            }

        }
    }
}

func API2(){
    queue.async{
        print("queue THREAD2")
        getData(offset: 20,limit: 12){
            (finalArray1) in
            print("IN third")
            for rest in finalArray1{
                print(rest.name)
            }
            self.queue.sync{
                self.tablD.updateValue(finalArray1, forKey: 2)
                self.myDataSource = myTableDataSource(data: self.tablD)
                print("SYNC DATASOURCE UPDATED 2")
                DispatchQueue.main.async {
                    if self.initialLoad == true{
                        self.initialLoad = false
                        self.myTableView.dataSource = self.myDataSource
                        print("TABLE RELOADING INITIAL ????")
                        self.myTableView.reloadData()
                    }
                }
                self.saveData(data: finalArray1, section: 2)
            }
        }
    }
}

func saveData(data:[userModel], section: Int){
        print("queue THREAD barrier ????????", section)
        //print("table datasrc entry:", self.myTableView.dataSource ?? "nil")
        DispatchQueue.main.sync {
                print("In else ????", section)
                    print("sections before IN ELSE",self.myTableView.numberOfSections)
                    self.myTableView.dataSource = self.myDataSource
                    //self.myTableView.reloadData()
                    //self.myTableView.beginUpdates()
                    print("reloading section number:", section)
                    self.myTableView.reloadSections([section], with: .automatic)
                    print("sections AFTER in ELSE",self.myTableView.numberOfSections)
                    //self.myTableView.endUpdates()
        }
        print("CONTINUING QUEUE WORK")
}

Выше мой код viewController.

Ошибка здесь ->

2018-08-01 16:13:14.381174+0530 docAnywhere[4299:118229] *** Assertion failure in -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.33.6/UITableView.m:13456 Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UITableView dataSource is not set'

Класс источника данных таблицы ->>

class myTableDataSource: NSObject, UITableViewDataSource{
var userData = [Any]()
var tableData = [[Any]]()
var tablD = [Int : [Any]]()
init(data: [Int : [Any]]) {
    tablD = data
}
//MARK: Table methods
func numberOfSections(in tableView: UITableView) -> Int {
    //print("sections:", tablD.count)
    return 3
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    print("reload in progress")
    if let rows = tablD[section] as? [Any]{
        return rows.count
    }
    return 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "usersCell") as! usersCell
    let rowData = tablD[indexPath.section] as! [Any]
    let thisUser = rowData[indexPath.row] as? userModel// userData[indexPath.row] as? userModel
    cell.userName?.text = thisUser?.name ?? ""
    print("cell no", thisUser?.name ?? "", "at", indexPath.section, indexPath.row)
    if (indexPath.row == (rowData.count - 1)) {
        print("LAST CELL RELOAD COMPLETE HERE", indexPath.section)
    }
    return cell
}

}

Иногда ошибка такая: -

2018-08-01 16:47:53.467219+0530 docAnywhere[6084:147469] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete section 0, but there are only 0 sections before the update'

ПРИМЕЧАНИЕ. Он отлично работает в случае 2 вызовов API и невозможности использования группы диспетчеризации, поскольку пользовательский интерфейс необходимо обновлять, как только любой вызов API завершается и данные становятся доступными. Несколько массивов или источников данных нельзя использовать для нескольких API.


person Ishan Baboota    schedule 01.08.2018    source источник
comment
сначала проверь розетку   -  person Wings    schedule 01.08.2018
comment
розетка в порядке. это работает в случае 2 вызовов API. вылетает только после введения 3-го API   -  person Ishan Baboota    schedule 01.08.2018
comment
Если вы выполняете загрузку API разбивки на страницы, я думаю, вы делаете неправильно, 3 API выполняются одновременно, а не последовательно   -  person Tj3n    schedule 01.08.2018
comment
Можете ли вы использовать второй API после завершения первого и третьего API после завершения второго и так далее? Только первый API в viewDidLoad.   -  person shivi_shub    schedule 01.08.2018
comment
это не пагинация.   -  person Ishan Baboota    schedule 01.08.2018
comment
Вызовы API @shivi_shub должны быть асинхронными.   -  person Ishan Baboota    schedule 01.08.2018
comment
@IshanBaboota, можете ли вы поделиться функцией источника данных tableview   -  person shivi_shub    schedule 01.08.2018
comment
@shivi_shub обновил вопрос   -  person Ishan Baboota    schedule 01.08.2018
comment
@IshanBaboota Я думаю, что перезагрузка представления таблицы и перезагрузка раздела таблицы происходят одновременно. Источники данных не совпадают   -  person shivi_shub    schedule 01.08.2018
comment
@shivi_shub да .. вопрос почему? когда обновление происходит в основном потоке в SYNC. тогда почему очередь возобновляется?   -  person Ishan Baboota    schedule 01.08.2018
comment
@IshanBaboota, вы пытаетесь выполнить задачу в основной очереди (main.sync), но она уже была в MainQueue, потому что вы не переключили очередь, и это может создать тупик (означает, что основная очередь ожидает себя).   -  person shivi_shub    schedule 01.08.2018
comment
Я в другой очереди.. проверьте, где я вызывал saveData   -  person Ishan Baboota    schedule 01.08.2018
comment
@IshanBaboota нет, ты в главной очереди. Вам нужно использовать глобальную очередь для перезагрузки таблицы   -  person shivi_shub    schedule 01.08.2018
comment
@shivi_shub все важные подробности в посте. Если у вас есть какое-либо решение, пожалуйста, опубликуйте ответ с исправлением в коде. Спасибо   -  person Ishan Baboota    schedule 01.08.2018


Ответы (1)


У вас происходит сбой, потому что вы постоянно меняете источник данных tableView. Мне не хватает части кода в вашем листинге кода... Если вы можете перепроектировать свой источник данных, чтобы вам не нужно было его менять, все будет в порядке. Например, вы можете перезагрузить раздел «1» с помощью API1, и когда он завершится, вы просто добавите элементы, которые вы получили от этого вызова API, в раздел 1... Все это может показаться запутанным :) Я хочу сказать, не меняйте источник данных...

person Dejan Agostini    schedule 01.08.2018
comment
На самом деле проблема начинается в методе saveData. Иногда команда print("sections before") выводит 0. Не знаю, как количество разделов os становится 0. Это приводит к сбою. Еще одна вещь, которую я заметил, заключается в том, что метод relodsections не завершается и возвращается преждевременно. Например, иногда он перезагружает только 3-4 ячейки в разделе и возвращает управление фоновому потоку. Почему это происходит? Я использовал метод синхронизации, поэтому он должен завершиться до возврата управления. Кроме того, это решение работает для 2 API, но дает сбой с 3 и более. - person Ishan Baboota; 02.08.2018