2

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

StoryImage

  1. I used storyboard in my project and made custom tableview cell to fill whole screen size. !
  2. I set self.tableview.pagingEnabled = YES.
  3. I used ReactiveCocoa, Parse.com and SCRecorder(for playing video like Vine) in this snippet of code.
  4. 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.

  1. 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;
}
Minwoo Park
  • 31
  • 1
  • 6
  • What is that you _want_ to do? That's what's unclear from your code. You want a viewPlayerView to appear where, exactly? – matt Jun 29 '14 at 18:50
  • This code is a bit of a mess. I can't even tell where any views are added to anything. I see no calls to `addSubview:`. – nhgrif Jun 29 '14 at 18:56
  • Yes I did not optimize the code itself right now. I will add the pictures and code for views – Minwoo Park Jun 29 '14 at 19:27
  • It is hard to tell from your description, but what I think may be happening is that when you are scrolling, by the time a video finishes loading the "original" cell is offscreen, but the cell object has been reused for a different index path. The video loads asynchronously and is assigned to the cell, even though it is now not the correct cell object for that video. Is cacheManagement your method? Can you modify it? – Paulw11 Jun 29 '14 at 21:14
  • possible duplicate of [Async image loading from url inside a UITableView cell - image changes to wrong image while scrolling](http://stackoverflow.com/questions/16663618/async-image-loading-from-url-inside-a-uitableview-cell-image-changes-to-wrong) – Paulw11 Jun 29 '14 at 21:15
  • Yes cacheManagement is my method. It just download the PFFile for video and save it to cache directory – Minwoo Park Jun 29 '14 at 22:39
  • Then in your callback function you should call `cellForRowAtIndexPath` on the tableView - if it returns null then the cell is off screen and you shouldn't update the cell. You will need to modify the cacheManagement to take an indexPath and the tableView – Paulw11 Jun 30 '14 at 11:22
  • Thanks. But the cell cannot be nil because I use storyboard and cell Identifier. I did experiment about this. Thanks though. The article that you show was really interesting and applicable! – Minwoo Park Jun 30 '14 at 16:26

0 Answers0