SNos
SNos

Reputation: 3470

SWIFT 2 - UICollectionView - slow scrolling

I have setup a uicollectionview in my project that get data from a JSON file. Everything works good however, the scrolling is very slow and when the view is scrolling the coming cell, for few moments shows the content of the cell before.

I have tried using dispatch_async but it still very slow and jumpy.

any Idea what am I doing wrong?

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let videoCell = collectionView.dequeueReusableCellWithReuseIdentifier("VideoCell", forIndexPath: indexPath) as UICollectionViewCell
        let communityViewController = storyboard?.instantiateViewControllerWithIdentifier("community_id")

        videoCell.frame.size.width = (communityViewController?.view.frame.size.width)!
        videoCell.center.x = (communityViewController?.view.center.x)!

        videoCell.layer.borderColor = UIColor.lightGrayColor().CGColor
        videoCell.layer.borderWidth = 2


        let fileURL = NSURL(string:self.UserVideosInfo[indexPath.row][2])
        let asset = AVAsset(URL: fileURL!)
        let assetImgGenerate = AVAssetImageGenerator(asset: asset)
        assetImgGenerate.appliesPreferredTrackTransform = true
        let time = CMTimeMake(asset.duration.value / 3, asset.duration.timescale)

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

            //self.showIndicator()

            let NameLabelString = self.UserVideosInfo[indexPath.row][0]
            let CommentLabelString = self.UserVideosInfo[indexPath.row][1]
            let DateLabelString = self.UserVideosInfo[indexPath.row][3]

            let buttonPlayUserVideo = videoCell.viewWithTag(1) as! UIButton
            let nameLabel = videoCell.viewWithTag(2) as! UILabel
            let commentUserVideo = videoCell.viewWithTag(3) as! UILabel
            let dateUserVideo = videoCell.viewWithTag(4) as! UILabel
            let thumbUserVideo = videoCell.viewWithTag(5) as! UIImageView
            let deleteUserVideo = videoCell.viewWithTag(6) as! UIButton

            buttonPlayUserVideo.layer.setValue(indexPath.row, forKey: "indexPlayBtn")
            deleteUserVideo.layer.setValue(indexPath.row, forKey: "indexDeleteBtn")

            dispatch_async(dispatch_get_main_queue()) {



                nameLabel.text = NameLabelString
                commentUserVideo.text = CommentLabelString
                dateUserVideo.text = DateLabelString

                self.shadowText(nameLabel)
                self.shadowText(commentUserVideo)
                self.shadowText(dateUserVideo)

                if let cgImage = try? assetImgGenerate.copyCGImageAtTime(time, actualTime: nil) {
                    thumbUserVideo.image = UIImage(CGImage: cgImage)
                }


            }

        }

        //THIS IS VERY IMPORTANT
        videoCell.layer.shouldRasterize = true
        videoCell.layer.rasterizationScale = UIScreen.mainScreen().scale


        return videoCell
    }

Upvotes: 0

Views: 1115

Answers (1)

Eugene Dudnyk
Eugene Dudnyk

Reputation: 6030

At first - you are working with UI objects from global queue and seems like without any purpose. That is forbidden - or behavior will be undefined.

Secondary, the mostly heavy operation is creation of thumbnail which you perform on main queue. Consider using of the AVAssetImageGenerator's method

public func generateCGImagesAsynchronouslyForTimes(requestedTimes: [NSValue], completionHandler handler: AVAssetImageGeneratorCompletionHandler)

instead of your own asyncs.

At third, viewWithTag is pretty heavy operation causing enumeration on subviews. Consider to declare properties in the cell for views which you need.

UPD: to declare properties in a cell, create subclass of UICollectionViewCell with appropriate properties as IBOutlets. Then, in your view controller viewDidLoad implementation, call

collecionView.registerClass(<YourCellSubclass>.dynamicType,  forCellWithReuseIdentifier:"VideoCell") 

Or, if your collection view cell is configured in the Storyboard, specify the class of the cell and connect its subviews to class' outlets directly in the cell's settings window in Interface Builder.

At fourth, your cells are being reused by a collection view. Each time your cell is going out of visible area, it is removed from collection view and is put to reuse queue. When you scroll back to the cell, your view controller is asked again to provide a cell. And you're fetching the thumbnail for the video again for each newly appeared cell. Consider caching of already fetched thumbnails by storing them in some array by collectionView's indexPath.item index.

Upvotes: 1

Related Questions