2

I have a JSON through which I get list of boards. Can be accessed by self.jsonGame.boards. Now I have to call all these boards and display the content from it.

But the boards are not consistently called. They’ll only show up sometimes.

func fetchBoard(){

    let repo = GameRepository()
    let prefs = UserDefaults.standard
    if self.jsonGame.boards.count > 0 {
        self.sortedBoardArr.reserveCapacity(self.BoardArr.count)

        for board in self.jsonGame.boards{

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

                        if errorCode == ErrorCode.NoError{
                            DispatchQueue.main.sync {

                                self.BoardArr.append(response)
                                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)
                }
            }
        }
    }
}

If anyone can help me figure out how to make sure the boards are called with a consistency.

I'm noob at async handling. Sorry for the trouble.

Prateekro
  • 566
  • 1
  • 6
  • 28
  • You're trying to request GetBoardInfo using main. Why not background or some other thread? – iWheelBuy May 08 '17 at 14:00
  • Because there is no way I am able to find the background task is done. So thought to keep it simple and execute in main async itself. – Prateekro May 08 '17 at 14:01

1 Answers1

4

I had a similar issue, where I populated an array with elements coming from different asynchronous network requests and when the requests were running concurrently, the final size of my array depended on the execution of the concurrent tasks.

I managed to solve my problem using a serial queue and Dispatch Groups. This is how I would change your code:

func fetchBoard(){

    let repo = GameRepository()
    let prefs = UserDefaults.standard
    if self.jsonGame.boards.count > 0 {
        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{
                    group.wait()
                    self.sortArr()
                    self.collectionView.reloadData()
                }
            }
        }
    }
}

These 2 answers for similar questions here on stack overflow were quite helpful for me when I had a similar issue: Blocking async requests and Concurrent and serial queues

Community
  • 1
  • 1
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Works like a charm. Thank you so much. Was stuck in this past 6 days. :) – Prateekro May 08 '17 at 14:41
  • Seems, there's a data race in line `self.BoardArr.append(response) `. Also the use of `serialQueue` doesn't seem to make sense for me. And, blocking the main thread with `group. wait` isn't a good idea either. :) You should probably submit the statement `self.BoardArr.append(response)` into a dedicated queue - probably, the main queue, and just call `group.notify` outside the for-loop and submitting a block on the main queue. – CouchDeveloper May 13 '17 at 18:04
  • I had problems previously when I was adding elements to an array concurrently in the completion block of several network requests, hence the serial queue. group.notify might work in this case, but I found group.wait to be more robust unless you need other calculations to happen on the main thread or to update the UI from other sources as well. – Dávid Pásztor May 13 '17 at 19:27