Summary I want to remove duplicate subviews in my custom table view cells. My old video player view and buttons in my custom table view cells appear all the time after I scroll the tableview. I do want to remove the old video view and buttons appear again and again.
What I did
- I used storyboard in my project and made custom tableview cell to fill whole screen size. !
- I set self.tableview.pagingEnabled = YES.
- I used ReactiveCocoa, Parse.com and SCRecorder(for playing video like Vine) in this snippet of code.
- I created IBOutlet for each subviews in my custom UITableViewCell in my custom tableviewCell class called MainViewCell. The tableview controller that used this custom tableviewCell is called MainViewController.
My Problem
Ok. I admit this should be a pretty easy problem. But I could not solve this even though I searched and applied all of the ways through google and stack overflow so far.My tableview cell creates subviews over and over again.
My Hypothesis
First of all, my main hypothesis for creating another videoPlayerview was that reusing cells create another playback view over and over again while they are reused.
- Reusing cell will create another SCVideoPlayerView(VideoPlayerView) again.
So, I tried to make nil the videoPlayerview in prepareForReuse like this
-(void)prepareForReuse
{
[super prepareForReuse];
self.buyButton = nil;
self.moreButton = nil;
self.messageButton =nil;
self.usernameButton = nil;
self.videoPlayerView = nil;
}
When I do this, way more weird thing happens. The underlying view exist and the new views was removed which was not what I wanted.
And when I remove videoPlayerview when the cell is not nil in the (MainViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath, When I do this, the view itself completely removed. I also tried this in (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell1 forRowAtIndexPath:(NSIndexPath *)indexPath. but, it shows same behavior.
I also tried to remove the sublayer which is (strong, nonatomic, readwrite) AVPlayerLayer * playerLayer in the SCVideoPlayerView class in prepareForReuse by using removeFromSuperLayer method. When I did this, it crashed my application.
For the buttons, I set the buttons as nil in the prepareForReuse method. But it also remove the new views, not old view. Here is the full snippets of code for this problem.
MainViewController
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"MainCell";
MainViewCell *cell = (MainViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
self.cell = cell;
PFObject *product = [self.products objectAtIndex:indexPath.row];
self.product = product;
self.title = [product objectForKey:@"productName"];
PFUser *uploader = [self.owners objectAtIndex:indexPath.row];
self.uploader = uploader;
[cell configureCellWithProduct:product andUploader:uploader withIndexPath:indexPath];
[[[cell.usernameButton rac_signalForControlEvents:UIControlEventTouchUpInside]doNext:^(id x) {
cell.usernameButton.enabled = NO;
}] subscribeNext:^(id x) {
cell.usernameButton.enabled = YES;
[self stopVideo];
[self performSegueWithIdentifier:@"myPine" sender:self];
}];
[[[cell.buyButton rac_signalForControlEvents:UIControlEventTouchUpInside]doNext:^(id x) {
cell.buyButton.enabled = NO;
}] subscribeNext:^(id x) {
cell.buyButton.enabled = YES;
[self stopVideo];
[self performSegueWithIdentifier:@"buyThisOne" sender:self];
}];
[[[cell.messageButton rac_signalForControlEvents:UIControlEventTouchUpInside]doNext:^(id x) {
cell.messageButton.enabled = NO;
}] subscribeNext:^(id x) {
cell.messageButton.enabled = YES;
[self stopVideo];
[self performSegueWithIdentifier:@"showMessages" sender:self];
}];
[[[cell.moreButton rac_signalForControlEvents:UIControlEventTouchUpInside] doNext:^(id x) {
cell.moreButton.enabled = NO;
}] subscribeNext:^(id x) {
cell.moreButton.enabled = YES;
[self stopVideo];
[self showActionSheet];
}];
return cell;
}
MainViewCell.h
@interface MainViewCell : UITableViewCell
{
SCPlayer *player;
}
@property (weak, nonatomic) IBOutlet SCVideoPlayerView *videoPlayerView;
@property (weak, nonatomic) IBOutlet UIImageView *profileImage;
@property (weak, nonatomic) IBOutlet UIButton *usernameButton;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *locationLabel;
@property (weak, nonatomic) IBOutlet UILabel *yearLabel;
@property (weak, nonatomic) IBOutlet UIButton *buyButton;
@property (weak, nonatomic) IBOutlet UIButton *messageButton;
@property (weak, nonatomic) IBOutlet UIButton *moreButton;
-(void)configureCellWithProduct:(PFObject *)product andUploader:(PFUser *)uploader withIndexPath:(NSIndexPath *)indexPath;
MainViewCell.m
-(void)configureCellWithProduct:(PFObject *)product andUploader:(PFUser *)uploader withIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"Configure cell is called");
CacheManagement *cacheManagement = [CacheManagement sharedStore];
self.uploader = uploader;
self.product = product;
NSNumber *price = [product objectForKey:@"productPrice"];
[self.usernameButton setTitle:[uploader objectForKey:@"name"] forState:UIControlStateNormal];
[self.usernameButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
self.priceLabel.text = [NSString stringWithFormat:@"$%@", price.stringValue];
self.yearLabel.text = [product objectForKey:@"productYear"];
self.locationLabel.text = [uploader objectForKey:@"currentCity"];
__block PFFile *videoFile =[product objectForKey:@"videoFile"];
EGOCache *cache = [EGOCache globalCache];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
NSString *fileName = [NSString stringWithFormat:@"Video%ld", [CacheManagement sharedStore].productCount- indexPath.row];
NSString *key = [fileName stringByAppendingPathExtension:@".mov"];
if(![cache hasCacheForKey:key])
{
[cacheManagement videoDownload:videoFile withIndexPath:indexPath forVideoView:self.videoPlayerView];
}
else
{
[self playVideoWithKey:key];
}
});
if([cache hasCacheForKey:self.product.objectId])
{
NSData *imageData = [cache dataForKey:@"images"];
self.avatars = [NSKeyedUnarchiver unarchiveObjectWithData:imageData];
NSLog(@"self.avatars : %@", self.avatars);
NSLog(@"We have cache for uploader!");
UIImage *profileImage = [self.avatars objectForKey:[self.uploader objectForKey:@"name"]];
dispatch_async(dispatch_get_main_queue(), ^{
self.profileImage.image = profileImage;
});
}
else
{
ImageUtil *downloader = [ImageUtil sharedStore];
[downloader profileImageDownloadforUser:self.uploader completion:^(UIImage *image) {
[cacheManagement saveCacheForProfileImage:image withObjectId:self.uploader.objectId];
dispatch_async(dispatch_get_main_queue(), ^{
self.profileImage.image = image;
});
}];
}
}
-(void)awakeFromNib
{
[super awakeFromNib];
NSLog(@"Awake from nib!");
player = self.videoPlayerView.player;
player.delegate = self.videoPlayerView;
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)];
gestureRecognizer.numberOfTapsRequired=1;
[self.videoPlayerView addGestureRecognizer:gestureRecognizer];
if([player isPlaying])
{
[self stopVideo];
}
}
-(void)playVideoWithKey:(NSString *)key
{
EGOCache *cache = [EGOCache globalCache];
if(self.videoPlayerView.player !=nil)
{
NSLog(@"Reinitializing video PlayerView");
SCVideoPlayerView *playerView = [self.videoPlayerView initWithPlayer:player];
playerView.frame = self.videoPlayerView.frame;
self.videoPlayerView= nil;
self.videoPlayerView = playerView;
}
[self setVideoPath:[cache cachePathForTheKey:key]];
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [NSURL fileURLWithPath:self.videoPath];
[player setItemByUrl:url];
player.shouldLoop = YES;
NSLog(@"Playing video");
[player play];
});
}
-(void)prepareForReuse
{
[super prepareForReuse];
self.buyButton = nil;
self.moreButton = nil;
self.messageButton =nil;
self.usernameButton = nil;
}