Swift 5-使tableview等待直到来自api调用的数据返回(使用多个tableview)

问题描述 投票:1回答:6

问题:加载View时发生致命错误。我知道问题是因为在尝试加载表视图时没有可用数据。但是,由于我在一个UI中使用了多个TableView,因此必须在CellForRowAt中强制返回单元格。

是否有更好的方法为每个TableView设置不同的数据?

感谢您的帮助!


import UIKit

class NewCustomTaskVC: UIViewController {


    @IBAction func CancelPressed (_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
    @IBOutlet weak var taskTypeSelectionBtn: UIButton!
    @IBOutlet weak var FrameSelectionBtn: UIButton!
    @IBOutlet weak var AssignSelectionBtn: UIButton!


    @IBAction func SelecttaskTypePressed(_ sender: Any) {
        if tableViewTaskType.isHidden {
            self.tableViewTaskType.isHidden = false
            self.tableViewTaskType.rowHeight = 43.5
        } else {
            self.tableViewTaskType.isHidden = true
        }
    }


    @IBAction func SelectFramePressed(_ sender: Any) {
        if tableViewFrame.isHidden {
            self.tableViewFrame.isHidden = false
        } else {
            self.tableViewFrame.isHidden = true
        }
    }

    @IBAction func SelectAssignToPressed(_ sender: Any) {
        if tableViewAssignTo.isHidden {
            self.tableViewAssignTo.isHidden = false
        } else {
            self.tableViewAssignTo.isHidden = true
        }
    }





    @IBOutlet weak var tableViewTaskType: UITableView!
    @IBOutlet weak var tableViewFrame: UITableView!
    @IBOutlet weak var tableViewAssignTo: UITableView!



    var cellID = ""
    var array = ["String", "Test", "Next","Test 2", "Test 3"]

    override func viewDidLoad() {
        super.viewDidLoad()

        getData()

        tableViewTaskType.isHidden = true
        tableViewFrame.isHidden = true
        tableViewAssignTo.isHidden = true

        tableViewTaskType.delegate = self
        tableViewFrame.delegate = self
        tableViewAssignTo.delegate = self

        tableViewTaskType.dataSource = self
        tableViewFrame.dataSource = self
        tableViewAssignTo.dataSource = self

        self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
        self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
        self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")

    }



    func getData () {
        //dispatchGroup.enter()
        var count = 0
        APICallBack.getFramesData(completion: { success in
            if success == true {
                print("frames success")
             count += 1
            } })

        APICallBack.getTaskTypeData { success in
            if success == true {
                print("task success")
             count += 1
            }
        }

        APICallBack.GETUserData(completion:  { success in
        if success == true {
            print("user success")
            count += 1
        } })

        if count == 3{

            DispatchQueue.main.async {
                self.tableViewTaskType.reloadData()
                self.tableViewAssignTo.reloadData()
                self.tableViewFrame.reloadData()
                print("ALL COMPLETE")

            }
        }
    }


}





   extension NewCustomTaskVC : UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
       return 1

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        var count = 1
               switch tableView {
               case tableViewTaskType:
                   count = TaskTypeData.typeModel.count

               case tableViewFrame:
                   count = FramesData.framesModel.count

               case tableViewAssignTo:
                   count = CustomerData.customerModel.count

               default:
                   print("none")
                   return count
               }
        //return 5
        return count
    }

**PROBLEM IS HERE 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell:UITableViewCell?

        if tableView == self.tableViewTaskType{
            cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
            cell!.textLabel!.text = TaskTypeData.typeModel[indexPath.row].TaskTypeName
           // cell!.textLabel?.text = array[indexPath.row]
        }

        if tableView == tableViewFrame{
             cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
            cell!.textLabel!.text = FramesData.framesModel[indexPath.row].FrameName
           // cell!.textLabel?.text = array[indexPath.row]
        }
        if tableView ==  self.tableViewAssignTo {
             cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
            cell!.textLabel!.text = UserData.userModel[indexPath.row].UserFirst
          //  cell.textLabel?.text = array[indexPath.row]
        }
//       let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
//        cell.textLabel?.text = array[indexPath.row]


        return cell!
    }
** TO HERE!



    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let item = array[indexPath.row]
        print(item)
        tableViewTaskType.isHidden = true

    }



   }


我的UI视图:

enter image description here

如果不强行得到的错误:

enter image description here

ios swift uitableview drop-down-menu
6个回答
0
投票

我假设您要在数据源数组为空时显示一个空的“占位符”单元格。您需要在cellForRow函数中明确检查该条件。

就协调来自多个API端点的提取,您可以使用DispatchGroup-一些注释代码表明您可能已经尝试过此操作。

override func viewDidLoad() {
    super.viewDidLoad()

    tableViewTaskType.isHidden = true
    tableViewFrame.isHidden = true
    tableViewAssignTo.isHidden = true

    tableViewTaskType.delegate = self
    tableViewFrame.delegate = self
    tableViewAssignTo.delegate = self

    tableViewTaskType.dataSource = self
    tableViewFrame.dataSource = self
    tableViewAssignTo.dataSource = self

    self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
    self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
    self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")

    getData()
}

func getData () {
    let dispatchGroup = DispatchGroup()

    dispatchGroup.enter()
    APICallBack.getFramesData(completion: { success in
        if success == true {
            print("frames success")
        } 
        dispatchGroup.leave()
    })

    APICallBack.getTaskTypeData { success in
        if success == true {
            print("task success")
        }
        dispatchGroup.leave()
    }

    APICallBack.GETUserData(completion:  { success in
        if success == true {
            print("user success")
        } 
        dispatchGroup.leave()
    })

    dispatchGroup.notify {
            self.tableViewTaskType.reloadData()
            self.tableViewAssignTo.reloadData()
            self.tableViewFrame.reloadData()
            print("ALL COMPLETE")
    }
}


extension NewCustomTaskVC : UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
   return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    switch tableView {
        case tableViewTaskType:
            return max(1,TaskTypeData.typeModel.count)

        case tableViewFrame:
            return max(1,FramesData.framesModel.count)

        case tableViewAssignTo:
            return max(1,CustomerData.customerModel.count)

        default:
            fatalError("Unexpected table view")
    } 
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    switch tableView {
        case self.tableViewTaskType:
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
            if !TaskTypeData.typeModel.isEmpty {
                cell.textLabel!.text = TaskTypeData.typeModel[indexPath.row].TaskTypeName
            }
            return cell

        case tableViewFrame:
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
            if !FramesData.framesModel.isEmpty {
                cell!.textLabel!.text = FramesData.framesModel[indexPath.row].FrameName
            }
            return cell

        case self.tableViewAssignTo:     
           let cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
           if !UserData.userModel.isEmpty {
               cell!.textLabel!.text = UserData.userModel[indexPath.row].UserFirst
           }
           return cell

        default:
           fatalError("Unexpected Tableview")
    }
}

0
投票

您可以在返回数据时将tableView.dataSource和tableView.delegate设置为self


0
投票

您的代码有多个问题。1)您在表视图注册单元格之前调用获取数据。因此,如果您的API立即加载数据,则表视图将调用dataSource方法

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int  
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell  

但自从

self.tableViewTaskType.register(UITableViewCell.self, forCellReuseIdentifier: "cell1")
self.tableViewFrame.register(UITableViewCell.self, forCellReuseIdentifier: "cell2")
self.tableViewAssignTo.register(UITableViewCell.self, forCellReuseIdentifier: "cell3")

在viewDidLoad的末尾调用,当您在cellForAtIndexPath方法中将单元格出队时,将会崩溃。

解决方案是将getData调用移至viewDidLoad方法的末尾。

2)如果要一次显示所有表数据(API完成加载getFramesData,getTaskTypeData和GETUserData时),则需要同步此回调。您可以使用DispatchGroup进行此操作。

    func getData () {
        let apiDispatchGroup = DispatchGroup()

        APICallBack.getFramesData { success in
            apiDispatchGroup.leave()
        }
        apiDispatchGroup.enter()

        APICallBack.getTaskTypeData { success in
            apiDispatchGroup.leave()
        }
        apiDispatchGroup.enter()

        APICallBack.GETUserData { success in
            apiDispatchGroup.leave()
        }
        apiDispatchGroup.enter()

        apiDispatchGroup.notify(queue: DispatchQueue.main) {
            self.tableViewTaskType.reloadData()
            self.tableViewAssignTo.reloadData()
            self.tableViewFrame.reloadData()
        }
    }

3)对于多个UITableView使用一个dataSOurce类并不是一个好主意,因为dataSource成为上帝对象。更好的方法是使用一个包含三个子UITableViewController的ContainerViewController,并在从API加载数据后将数据传递给子类。]

在一个屏幕中具有多个视图控制器是非常好的。因此,我建议您创建三个视图控制器,每个表视图一个。每个表视图都有自己的数据源。然后使用自定义容器视图控制器,如下所述:https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller

尝试通过这种方式重新加载TableView数据,

    func getData () {
        //dispatchGroup.enter()
        var count = 0
        APICallBack.getFramesData(completion: { success in
            if success == true {
                print("frames success")
             count += 1
             self.reloadTableViewsIfNeeded(count)
            } })

        APICallBack.getTaskTypeData { success in
            if success == true {
                print("task success")
             count += 1
             self.reloadTableViewsIfNeeded(count)
            }
        }

        APICallBack.GETUserData(completion:  { success in
        if success == true {
            print("user success")
            count += 1
            self.reloadTableViewsIfNeeded(count)
        } })


    }

    func reloadTableViewsIfNeeded (_ conunt: Int) {
        if count == 3{

            DispatchQueue.main.async {
                self.tableViewTaskType.reloadData()
                self.tableViewAssignTo.reloadData()
                self.tableViewFrame.reloadData()
                print("ALL COMPLETE")

            }
        }
    }

通过使用此方法,您将获得一个事件,在获取所有数据后将重新加载表视图。

让我知道是否有帮助。

享受并分享...

您总是可以返回默认的非样式UITableViewCell。同时停止强行展开。如果要让或让让,则应始终保持警惕。

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        var cell:UITableViewCell?


        ...

        return UITableViewCell()
    }

0
投票

在一个屏幕中具有多个视图控制器是非常好的。因此,我建议您创建三个视图控制器,每个表视图一个。每个表视图都有自己的数据源。然后使用自定义容器视图控制器,如下所述:https://developer.apple.com/documentation/uikit/view_controllers/creating_a_custom_container_view_controller


-1
投票

尝试通过这种方式重新加载TableView数据,


-2
投票

您总是可以返回默认的非样式UITableViewCell。同时停止强行展开。如果要让或让让,则应始终保持警惕。

© www.soinside.com 2019 - 2024. All rights reserved.