Changing playerItem of AVPlayer in UITableView Changing playerItem of AVPlayer in UITableView multithreading multithreading

Changing playerItem of AVPlayer in UITableView


If you do some basic level of profiling, I think you can narrow down the problem. For me, I had a similar issue where replaceCurrentItemWithPlayerItem was blocking the UI thread. I resolved it by examining my code to find out which line was taking time. For me the AVAsset loading was taking time. So I used the loadValuesAsynchronouslyForKeys method of AVAsset to resolve my issue.

Hence can you try the following:

-(void)initializeNewObject:(CustomObject*)o{    //If this cell is being dequeued/re-used, its player might still be playing the old file    [self.player pause];    self.currentObject = o;    /*    //Setting text-variables for title etc. Removed from this post, but by commenting them out in the code, nothing improves.    */    //Replace the old playerItem in the cell's player    NSURL *url = [NSURL URLWithString:self.currentObject.url];    AVAsset *newAsset = [AVAsset assetWithURL:url];    [newAsset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{        AVPlayerItem *newItem = [AVPlayerItem playerItemWithAsset:newAsset];        [self.player replaceCurrentItemWithPlayerItem:newItem];    }];    //The last line above, replaceCurrentItemWithPlayerItem:, is the 'bad guy'.    //When commenting that one out, all lag is gone (of course, no videos will be playing either)    //The lag still occurs even if I never call [self.player play], which leads me    //to believe that nothing after this function can cause the lag    self.isPlaying = NO;}


In your CustomCell.m you should use thumbnails to display an image for the specific cell video, you could add the thumbnail to a button inside your cell, then build a custom delegate in CustomCell.h that will be called when you tap on the newly created button something like:

@class CustomCell;@protocol CustomCellDelegate <NSObject>- (void)userTappedPlayButtonOnCell:(CustomCell *)cell;@end

also in your your .h add the action for the button:

@interface CustomCell : UITableViewCell@property (strong, nonatomic) IBOutlet UIButton *playVideoButton; - (IBAction)didTappedPlayVideo; - (void)settupVideoWithURL:(NSString *)stringURL; - (void)removeVideoAndShowPlaceholderImage:(UIImage *)placeholder;@end

also in "didTappedPlayVideo" you do the next:

- (void)didTappedPlayVideo{[self.delegate userTappedPlayButtonOnCell:self];}

the method: settupVideoWithURL is used to init you playerand the method: removeVideoAndShowPlaceholderImagewill stop the video and make the AVPlayerItem and AVPlayer nil.

Now when the user taps a cell you send the call back to the UIViewController where you have the tableView, and in the delegate method you should do the next:

    - (void)userTappedPlayButtonOnCell:(CustomCell *)cell{    //check if this is the first time when the user plays a video    if(self.previousPlayedVideoIndexPath){          CustomCell *previousCell = (CustomCell *)[tableView cellForRowAtIndexPath:self.previousPlayedVideoIndexPath];          [previousCell removeVideoAndShowPlaceholderImage: [UIImage imageNamed:@"img.png"]];    }    [cell settupVideoWithURL:@"YOURvideoURL"];    self.previousPlayedVideoIndexPath = cell.indexPath;    }

P.S.:

On older devices(almost all of them until the new iPad Pro) is not indicated to have multiple instances of AVPlayer.Also hope that this chunks of code can guide or help you in your quest :)


You should profile your app using the time profiler to see where the lagging is actually occurring.

The documentation for replaceCurrentItemWithPlayerItem: clearly states that it executes asynchronously, so it shouldn't be the source of your main queue jumpiness.

The item replacement occurs asynchronously; observe the currentItem property to find out when the replacement will/did occur.

Documentation here

If you still can't figure it out, post more code, and in particular at least your cellForRowAtIndexPath method.

UPDATE

As per @joey's comment below, the previous content of this answer is no longer valid. The documentation no longer states that the method is asynchronous, so it may not be.