I have a UITableView
containing a number of videos to play when scrolling. As the cells in the tableView are being re-used, I only instantiate one AVPlaye
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 player
and the method: removeVideoAndShowPlaceholderImage
will 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;
}
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 :)
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;
}
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.