Prateekro
Prateekro

Reputation: 566

View Freezes with multiple DispatchQueue.main.async use

View Freezes while data is fetched and displayed. In my understanding fetchBoard() and initUserInfo() do not execute in parallel. (As view only loads when fetchBoard() loads the boards) I'm concerned if the use of DispatchQueue.main.async multiple times is freezing the view. Also, How do I make it work smoothly.

class MultipleCardsController2vs2: BaseController, UICollectionViewDataSource , UICollectionViewDelegate {

override func viewDidLoad() {
    super.viewDidLoad()

    let repo = GameRepository()
    repo.CreateGame(gameID : self.jsonGame.Id , completion: { (jsonGame, err) -> Void in
        if(err == ErrorCode.NoError){
            DispatchQueue.main.async{
                self.jsonGame = jsonGame                    
            }
        }
    })

    //These are the two functions I want these 2 to work in parallel 

    self.fetchBoard()           //Function 1
    self.initUserInfo()         //Function 2


    collectionView.delegate = self
    collectionView.dataSource = self


} // .viewDidLoad


func fetchBoard(){

    let repo = GameRepository()
    self.sortedBoardArr.reserveCapacity(self.BoardArr.count)
    let serialQueue = DispatchQueue(label: "serialQueue")
    let group = DispatchGroup()
    for board in self.jsonGame.boards{
        group.enter()
        serialQueue.async {

            repo.GetBoardInfo(gameID: self.jsonGame.Id, boardID: board ,  completion : {(response , errorCode ) -> Void in

                if errorCode == ErrorCode.NoError{
                        self.BoardArr.append(response)
                        group.leave()
                    }
            })

            DispatchQueue.main.async{

                //Main async - 1

                group.wait()
                self.sortArr()
                self.collectionView.reloadData()
            }
        }
    }
}


func sortArr(){
    if self.jsonGame.boards.count == self.BoardArr.count{

        for board in self.jsonGame.boards{
            for boardarr in self.BoardArr{
                if boardarr.id == board{
                    self.sortedBoardArr.append(boardarr)
                }
            }
        }
    }

}

fileprivate func initUserInfo()
{
    DispatchQueue.main.async{

                //Main async - 2

            self.name1.text = self.CurrentUser.UserName
            self.imgPlayie1.image = UserManager.GetAvatar(user: self.CurrentUser)
    }
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.jsonGame.boards.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Round2Cell", for: indexPath) as! Round1vs1cell

        cell.background.backgroundColor = UIColor(white: 1, alpha: 0.0)
        cell = self.populateGameCell(game_res, cell , indexPath)
    return cell
}

fileprivate func populateGameCell(_ game_res: Game_Res, _ cell: Round1vs1cell , _ indexPath : IndexPath ) -> Round1vs1cell
{     
    DispatchQueue.main.async {

         //Main async - 3

        cell.background.backgroundColor = UIColor(white: 1, alpha: 0.0)
        cell.word_1.text = game_res.words[0].word
        cell.color_1.image = UIImage(named: "")
        cell.life_1.image =  UIImage(named: "")
        cell.name.text = ""
        cell.op_name.text = game_res.master[index].username
        cell.timeout_left.image = UIImage(named: "Hourglass.png")
        cell.round.text = "Round: \(indexPath.row + 1)"
    }
    return cell
}

}

Looking for the smooth working and not freezing the view. I'm noob at working with Dispatch. Any help is welcome. Thanks in advance.

Upvotes: 3

Views: 1999

Answers (1)

shallowThought
shallowThought

Reputation: 19602

Use notify() instead of wait() to not block the main thread.

Playground example:

import PlaygroundSupport

func longRunningTask(completion: () -> Void) {
    sleep(1)
    completion()
}

func foo(){
    let queue = DispatchQueue(label: "myQueue")
    let group = DispatchGroup()
    let array = [1, 2, 3]

    for i in array {
        print(i)
        group.enter()
        queue.async {
            longRunningTask {
                print("done \(i)")
                group.leave()
            }
        }
    }

    group.notify(queue: DispatchQueue.main) {
        print("done!")
    }
}

foo()

PlaygroundPage.current.needsIndefiniteExecution = true

Prints:

1
2
3
done 1
done 2
done 3
done!

Additional Info why you are causing a deadlock can be found in this answer.

Upvotes: 3

Related Questions