Reputation: 821
I'm trying to create a simple app with photo filters, like Instagram. So, I capture my image then I need to implement filter to this image. On the bottom I have a UICollectionView(horizontal scroll) where I can see what filters I have and how they will look on my image.
But when I scroll my UICollectionView - it freezes and my filters applying on every new cell(because of reusing process). But how Instagram does it that when I scroll the filters they does not freeze?
I've tried this:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: imageFilterCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! imageFilterCell
let queue = NSOperationQueue()
let op1 = NSBlockOperation { () -> Void in
let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
cell.imageView.image = img1
})
}
queue.addOperation(op1);
return cell
}
but it still freezes on scroll and I see how every time my filters are applying to my cells. Can I do it just one time and then on scroll to do nothing, just showing how the photo will looks after implementing the filter?
Upvotes: 1
Views: 3136
Reputation: 133
you can cache data (Images) in memory its problem have a lovely relation with read data(images) :D
Upvotes: 0
Reputation: 4522
You could do one of the two things:
Do not use the reuse feature of the collection view. Simply create
an array of cells and pass those cells to cellForRowAtIndexPath
. This should work fine if you
don't have a large number of filters. Something like:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell: imageFilterCell? = nil
if (cellsArray.count <= indexPath.row) {
//This assumes imageFilterCell is created in code
//If you use storyboards or xibs load it accordingly
cell = imageFilterCell()
cellsArray.append(cell)
} else {
cell = cellsArray[indexPath.row]
}
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])
dispatch_async(dispatch_get_main_queue()) {
cell!.imageView.image = img1
}
}
return cell
}
Implement a cancel mechanism for the async operation, because if the cell is reused while the background thread is still applying the filter the final cell will end up having multiple filters. For this you could use the cancel
method from the NSOperation
class. For this you could create a property on your custom cell called operation
something like:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: imageFilterCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! imageFilterCell
cell.operation.cancel()
//make the queue an instance variable
//let queue = NSOperationQueue()
let op1 = NSBlockOperation { () -> Void in
let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
cell.imageView.image = img1
})
}
queue.addOperation(op1);
cell.operation = op1
return cell
}
Upvotes: 3
Reputation: 2317
You are processing in the main thread, this is why it freezes.
Use a Concurrent Dispatch Queue for a more fluid experience.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell: imageFilterCell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! imageFilterCell
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let img = UIImage(data: UIImageJPEGRepresentation(self.image!, 0.1)!)
let img1 = self.applyFilterTo(img!, filter: self.filtersImages[indexPath.row])
dispatch_async(dispatch_get_main_queue()) {
cell.imageView.image = img1
}
}
return cell
}
Upvotes: 0