如何在从Web获取数据后才显示tableView? (迅速)

问题描述 投票:0回答:3

加载嵌套在表视图单元格中的Collection视图时遇到了困难。单元格内的内容只会在滚动表格几次后显示。我的方法是使用DispatchGroup()来获取后台线程中的数据,但它不起作用。为了在不滚动表格的情况下一次显示所有信息,有什么可做的?

viewDidLoad中

override func viewDidLoad() {

    super.viewDidLoad()

    _tableView.isHidden = true
    _tableView.dataSource = nil
    _tableView.delegate = nil
    SVProgressHUD.show()
    view.backgroundColor = UIColor.flatBlack()

    getData()

    dispatchGroup.notify(queue: .main) {
        SVProgressHUD.dismiss()
        self._tableView.isHidden = false
        self._tableView.dataSource = self
        self._tableView.delegate = self
        self._tableView.reloadData()

    }
}

UICollectionView和UITableView数据源/ OtherMethods

func getData(){

        dispatchGroup.enter()

        backend.movieDelegate = self

        backend.actorDelegate = self

        backend.getMoviePopularList()

        backend.getMovieTopRatedList()

        backend.getMovieUpcomingList()

        backend.getPopularActors()

        backend.getMovieNowPlayingList()

        dispatchGroup.leave()
    }


    func transferMovies(data: [String:[MovieModel]]) {
        dispatchGroup.enter()
        popularMovies = data
        dispatchGroup.leave()
    }

    func transferActors(data: [ActorModel]) {
        dispatchGroup.enter()
        popularActors = data
        dispatchGroup.leave()

    }



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

        guard let cell = tableView.dequeueReusableCell(withIdentifier: "DiscoverCell") as? DiscoverViewCell else { return UITableViewCell()}

        cell.categoryLabel.text = cell.categories[indexPath.item]
        //categories[indexPath.item]
        cell._collectionView.delegate = self
        cell._collectionView.dataSource = self
        cell._collectionView.tag = indexPath.row
        cell._collectionView.reloadData()

        self.setUpCell(cell)

        return cell
    }


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MovieCell", for: indexPath) as? MovieCollectionViewCell else { return UICollectionViewCell()}

        if collectionView.tag == 0{

            if let movieDetails = popularMovies["Popular"]?[indexPath.item] {
                cell.updateMovieCollectionCell(movie: movieDetails)
            }
        } else if collectionView.tag == 1{

            if let movieDetails = popularMovies["Top rated"]?[indexPath.item] {

                cell.updateMovieCollectionCell(movie: movieDetails)
            }
        } else if collectionView.tag == 2{

            if let movieDetails = popularMovies["Upcoming"]?[indexPath.item] {

                cell.updateMovieCollectionCell(movie: movieDetails)

            } else if collectionView.tag == 3{

                cell.movieTitleLabel.text = popularActors?[indexPath.item].name ?? ""
                cell.moviePicture.image = popularActors?[indexPath.item].poster

            }
        } else if collectionView.tag == 4{

            if let movieDetails = popularMovies["Now playing"]?[indexPath.item] {
                cell.updateMovieCollectionCell(movie: movieDetails)
            }

        }

        return cell
    }

电影CollectionViewCell

class MovieCollectionViewCell: UICollectionViewCell {

        @IBOutlet weak var moviePicture: UIImageView!
        @IBOutlet weak var movieTitleLabel: UILabel!

        func updateMovieCollectionCell(movie: MovieModel){
            moviePicture.image = movie.poster
            movieTitleLabel.text = movie.name
        }

    }

DiscoverViewCell

class DiscoverViewCell: UITableViewCell {

        @IBOutlet weak var categoryLabel: UILabel!
        @IBOutlet weak var _collectionView: UICollectionView!

        let categories = ["Popular", "Top Rated", "Upcoming", "Popular People", "Now playing"]

        @IBAction func seeMoreAction(_ sender: Any) {

        }
    }

我的目的是显示一个加载动画,直到获取所有数据,并显示包含带有从web获取的数据的集合视图的表视图单元格。

打开应用程序时,所需的结果应如下所示

The desired result should look like this when opening the app

ios swift multithreading uitableview uicollectionview
3个回答
0
投票

据我所知,你正在使用dispatchGroup错误。

总结notify()

  • 当组中当前排队的所有块都完成时,它会运行关联的块
  • 块只运行一次然后释放
  • 如果组的队列为空,则立即运行该块

我看到的问题是,对于写入fetch代码的方式,当您调用notify时,该组认为其队列为空。所以notify()块立即运行,然后你只看到在滚动期间重新加载时填充的单元格。

有两种方法可以填充dispatchGroup的队列:

  • 调用DispatchQueue.async()并传递该组以直接将一个块排队并将其与该组关联
  • 块开始时手动调用enter(),结束时手动调用leave(),这会增加/减少组内部计数器

第一种方法更安全,因为您不必自己跟踪块,但如果您无法控制块运行的队列,则第二种方法更灵活。

由于您使用的是enter/leave,因此您需要确保为每个单独的工作项调用enter()(在您的情况下,对backend进行异步调用),并且只在每个工作项完成时调用leave()。我不确定你是如何使用委托方法的,但是每个backend调用似乎都没有,因为有5个不同的调用,只有2个委托方法。如果后端调用中发生错误,它看起来也不会调用委托方法。

我建议更改backend调用以改为使用完成块,但如果你想坚持使用委托模式,那么你可以这样做:

func getData(){
    backend.movieDelegate = self
    backend.actorDelegate = self

    dispatchGroup.enter()
    backend.getMoviePopularList()

    dispatchGroup.enter()
    backend.getMovieTopRatedList()

    dispatchGroup.enter()
    backend.getMovieUpcomingList()

    dispatchGroup.enter()
    backend.getPopularActors()

    dispatchGroup.enter()
    backend.getMovieNowPlayingList()

    dispatchGroup.notify(queue: .main) {
        SVProgressHUD.dismiss()
        self._tableView.isHidden = false
        self._tableView.dataSource = self
        self._tableView.delegate = self
        self._tableView.reloadData()
    }
}

func transferPopularMovies(data: [MovieModel]) {
    popularMovies = data
    dispatchGroup.leave()
}

func transferTopRatedMovies(data: [MovieModel]) {
    topRatedMovies = data
    dispatchGroup.leave()
}

func transferUpcomingMovies(data: [MovieModel]) {
    upcomingMovies = data
    dispatchGroup.leave()
}

func transferActors(data: [ActorModel]) {
    popularActors = data
    dispatchGroup.leave()
}

func transferNowPlayingMovies(data: [MovieModel]) {
    nowPlayingMovies = data
    dispatchGroup.leave()
}

即使出现错误以确保enter/leave调用是平衡的,也不要忘记调用委托方法。如果你比enter更频繁地调用leave,那么notify块永远不会运行。如果你经常打电话给leave,你会崩溃。


0
投票

试试这个......从后端获取数据并分配给moviedetails后,将你的委托和数据源设置为self和reload表。


0
投票

将此行设置为getData()函数的底部并运行

    self._tableView.isHidden = false
    self._tableView.dataSource = self
    self._tableView.delegate = self
    self._tableView.reloadData()

并从viewdidload()中删除

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