I think it's because you're not telling the collection view to reload. Your refresh method updates the model but not the view.
If you're fetching the data on a background thread, the main thread can continue it's lifecycle, which involves querying the collection view datasource and delegate methods then updating the view, but it will be doing this too soon in your case, as the model isn't ready. That's why you need to tell it to do that again, when the model is ready, at the end of your data fetch. Since you block the thread when doing it synchronously, it won't reach the collection view methods until the model is ready, which is why it works that way.