Reputation: 412
I’m a few days old in iOS programming so please bear with me. I’m trying to show a UICollectionView with a matrix of some images.
Problem is getting the images to show up when initialisation of UICollectionView happens from inside a dispatch_async. Initialisation works fine from viewDidLoad(). Both the println output can be observed in Xcode console so background process and subsequent UI updates on main ought to happen.
I have left out other functions because apparently they are not the problem (init works from viewDidLoad)
Using Xcode 6.4. Target is iPhone 5, 8.4.1
Here is the relevant code:
class MyCollectionViewController: UICollectionViewController, UICollectionViewDataSource, UICollectionViewDelegate {
class MyClass {
var x: Int
var y: Int
var thumbnail: String
init(…) {
}
}
var list = [MyClass]()
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
// self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
// Do any additional setup after loading the view.
/* uncommenting this works fine
list.append(MyClass(x: 1000, y: 10, thumbnail: “img1.jpg”))
list.append(MyClass(x: 1001, y: 11, thumbnail: “img2.jpg”))
list.append(MyClass(x: 1002, y: 12, thumbnail: “img3.jpg”))
list.append(MyClass(x: 1003, y: 13, thumbnail: “img4.jpg”))
list.append(MyClass(x: 1004, y: 14, thumbnail: “img5.jpg”))
list.append(MyClass(x: 1005, y: 15, thumbnail: “img6.jpg”))
*/
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), {
println("This is run on the background queue")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println("This is run on the main queue, after the previous code in outer block")
// This code block below just shows a black screen
self.list.append(MyClass(x: 1000, y: 10, thumbnail: “img1.jpg”))
self.list.append(MyClass(x: 1001, y: 11, thumbnail: “img2.jpg”))
self.list.append(MyClass(x: 1002, y: 12, thumbnail: “img3.jpg”))
self.list.append(MyClass(x: 1003, y: 13, thumbnail: “img4.jpg”))
self.list.append(MyClass(x: 1004, y: 14, thumbnail: “img5.jpg”))
self.list.append(MyClass(x: 1005, y: 15, thumbnail: “img6.jpg”))
})
})
…
}
UPDATE: Here is the fixed code
class MyCollectionViewController: UICollectionViewController, UICollectionViewDataSource, UICollectionViewDelegate {
class MyClass {
var x: Int
var y: Int
var thumbnail: String
init(…) {
}
}
var list = [MyClass]()
override func viewDidLoad() {
super.viewDidLoad()
// Register cell classes
// self.collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
// Do any additional setup after loading the view.
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), {
println("This is run on the background queue")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println("This is run on the main queue, after the previous code in outer block")
self.list.append(MyClass(x: 1000, y: 10, thumbnail: “img1.jpg”))
self.list.append(MyClass(x: 1001, y: 11, thumbnail: “img2.jpg”))
self.list.append(MyClass(x: 1002, y: 12, thumbnail: “img3.jpg”))
self.list.append(MyClass(x: 1003, y: 13, thumbnail: “img4.jpg”))
self.list.append(MyClass(x: 1004, y: 14, thumbnail: “img5.jpg”))
self.list.append(MyClass(x: 1005, y: 15, thumbnail: “img6.jpg”))
// This statement solved the issue
self.collectionView?.reloadData()
})
})
…
}
Upvotes: 1
Views: 1363
Reputation: 1585
UICollectionViewController or UITableViewController tries to call the datasource when the viewDidLoad() is called and hence is synchronous. If somehow the class needs to fetch data from server and does that in good async call, it means the data is going to arrive later and after the datasources methods to load the cells are called.
Now to reload the data after the arrival from the server or async task, call the collectionView's reloadData method like so.
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), {
println("This is run on the background queue")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
println("This is run on the main queue, after the previous code in outer block")
// This code block below just shows a black screen
self.list.append(MyClass(x: 1000, y: 10, thumbnail: “img1.jpg”))
self.list.append(MyClass(x: 1001, y: 11, thumbnail: “img2.jpg”))
self.list.append(MyClass(x: 1002, y: 12, thumbnail: “img3.jpg”))
self.list.append(MyClass(x: 1003, y: 13, thumbnail: “img4.jpg”))
self.list.append(MyClass(x: 1004, y: 14, thumbnail: “img5.jpg”))
self.list.append(MyClass(x: 1005, y: 15, thumbnail: “img6.jpg”))
})
self.collectionView.reloadData() //telling to reload the data once again
})
A subclass of UICollectionViewController gets a default hook to the collectionView outlet and we used it.
However sometimes what i do is, put a property observer in the data array and then call the reload there.
var list = [MyClass](){
didSet{
//do some work like validation
collectionView.reloadData()
}
}
Anyways, i hope it helps. Cheers!
Upvotes: 2