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

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

Я смог добиться этого с 2 API, но когда я использую 3 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.

1 ответ

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

Другие вопросы по тегам