ios - 离开 UIViewController 时应用程序崩溃

标签 ios uitableview avplayer

我的应用程序在离开 UIViewController 时崩溃并出现以下错误。

[FeedSingleViewCell retain]: message sent to deallocated instance 0x7ffbb8950a00

在我的 UIViewController 中,我使用了 UITableView 并且有自动播放功能,当视频结束或用户离开当前 UIViewController 时,在 ViewWillDisAppear 我将 AVPlayer 设为 nil,删除 AVPlayer 子层,但它仍然崩溃。

示例代码

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.lblNoVideo.text = [NSString stringWithFormat:@"Video from %@ is may be hidden by you.", self.objOtherUser.strUserName];
    
    arrOtherVideos          = [[NSMutableArray alloc] init];
    arrSelectedIndexPath    = [[NSMutableArray alloc] init];
    arrAddedPlayerIndexPath = [[NSMutableArray alloc] init];
    self.arrAddedVideo      = [[NSMutableArray alloc] init];
    self.arrPlayedVideo     = [[NSMutableArray alloc] init];
    self.arrAddedVideoCell  = [[NSMutableArray alloc] init];
    
    self.navigationController.interactivePopGestureRecognizer.delegate = self;
    [self.navigationController.interactivePopGestureRecognizer setEnabled:YES];
    
    [self initFooterView];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(whenFinishOtherUserVideo:) name:kVideoFinishNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nightModeInOtherUserVideosVC) name:kNotificationNightMode object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refershOtherUserVideos) name:kRefreshUploadedVideoData object:nil];
    
    self.lblNoVideo.hidden = YES;
    
    nMaxID = 0;
    isNewVideosAvailable = false;
    [self getOtherUserVideos:nMaxID];
    
    self.lblNavTitle.text = [NSString stringWithFormat:@"%@'s Videos", self.objOtherUser.strUserName];
    
    self.tblVW.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
    self.tblVW.separatorColor = [UIColor clearColor];
    
    refreshControl = [[UIRefreshControl alloc] init];
    if ([[SharedClass objSharedClass] isNightModeEnable]) {
        [refreshControl setTintColor:[UIColor whiteColor]];
    }
    else {
        [refreshControl setTintColor:kAppThemeColor];
    }
    [refreshControl addTarget:self action:@selector(refershOtherUserVideos) forControlEvents:UIControlEventValueChanged];
    [self.tblVW addSubview:refreshControl];
    
    self.tblVW.estimatedRowHeight = 278.0f;
    self.tblVW.rowHeight = UITableViewAutomaticDimension;
    
    //Set status bar
    [self setNeedsStatusBarAppearanceUpdate];
}


-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    self.tabBarController.tabBar.hidden = NO;
    
    //CALL TO REMOVE ASSIGNED OBSERVER
    [currentCell removeAssignedObserverToPlayerItem];
    [currentCell pause];
    [currentCell.loadingIndicatorView removeFromSuperview];
    [currentCell.btnPlayPause setSelected:false];
    [currentCell.seekSlider removeFromSuperview];
    currentCell.playerLayer.sublayers = nil;
    currentCell.player = nil;
    [currentCell unHideVideoControls];
    [self.arrPlayedVideo removeAllObjects];
    
    // To Hide Opened View More Option View
    [arrSelectedIndexPath removeAllObjects];
}


-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (arrOtherVideos.count <= 0) {
        return 0;
    }
    else {
        return arrOtherVideos.count;
    }
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"FeedSingleViewCell";
    
    FeedSingleViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    
    if (cell == nil) {
        cell = [[[NSBundle mainBundle] loadNibNamed:cellIdentifier owner:self options:nil] objectAtIndex:0];
    }
    
    UserVideoObject *objMyUploadedVideo = [arrOtherVideos objectAtIndex:indexPath.row];
    
    cell.vwMainBack.layer.cornerRadius = 3.0f;
    cell.vwMainBack.clipsToBounds = YES;
    
    cell.activityIndicator.hidden = YES;
    cell.btnPlayPause.hidden = NO;
    
    if ([arrAddedPlayerIndexPath containsObject:objMyUploadedVideo]) {
        [cell.btnPlayPause setSelected:true];
    }
    else {
        [cell.btnPlayPause setSelected:false];
    }
    
    if (objMyUploadedVideo.strVideoURL != nil) {
        cell.isVideoAvailable = true;
    }
    else {
        cell.isVideoAvailable = false;
    }
    
    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onOtherUserVideosPlayerViewTap:)];
    gesture.numberOfTapsRequired = 1;
    cell.playerView.tag = indexPath.row;
    [cell.playerView addGestureRecognizer:gesture];
    
    cell.lblCurrentPlayTime.tag = indexPath.row;
    cell.btnPlayPause.tag = indexPath.row;
    [cell.btnPlayPause addTarget:self action:@selector(onOtherUserProfileVideoPlayPauseButtonClick:) forControlEvents:UIControlEventTouchUpInside];
    
    [cell.imgVWVideoCoverImage sd_setImageWithURL:[NSURL URLWithString:objMyUploadedVideo.strVideoCoverImage] placeholderImage:[UIImage imageNamed:@""]];
    
    cell.imgVWUserProfilePhoto.layer.cornerRadius = cell.imgVWUserProfilePhoto.frame.size.width / 2.0f;
    cell.imgVWUserProfilePhoto.clipsToBounds = YES;
    
    [cell.imgVWUserProfilePhoto sd_setImageWithURL:[NSURL URLWithString:objMyUploadedVideo.strUserImage] placeholderImage:[UIImage imageNamed:kUserPlaceHolderImage]];
    
    cell.lblNumberOfViews.text = [NSString stringWithFormat:@"%@ Views", [[SharedClass objSharedClass] abbreviateNumber:objMyUploadedVideo.nVideoViews]];
    cell.lblVideoDuration.text = objMyUploadedVideo.strVideoLength;
    
    if ([objMyUploadedVideo.strVideoCreatedTime isEqualToString:@""] || [objMyUploadedVideo.strVideoCreatedTime isKindOfClass:[NSNull class]] || objMyUploadedVideo.strVideoCreatedTime == nil) {
        cell.lblVideoPostedDate.text = @"";
    }
    else {
        cell.lblVideoPostedDate.text  = [[SharedClass objSharedClass] convertDateStringToUTCDate:objMyUploadedVideo.strVideoCreatedTime];
    }
    
    cell.lblVideoDescription.text = objMyUploadedVideo.strVideoTitle;
    
    cell.vwVideoTime.layer.cornerRadius = 3.0f;
    
    cell.vwMainBack.layer.borderWidth = 0.3;
    cell.vwMainBack.layer.borderColor = [[[UIColor lightGrayColor] colorWithAlphaComponent:0.4] CGColor];
    
//    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onOtherUserUploadedProfilePhotoClick:)];
//    tap.numberOfTapsRequired = 1;
//    cell.imgVWUserProfilePhoto.tag = indexPath.row;
//    [cell.imgVWUserProfilePhoto addGestureRecognizer:tap];
    
    cell.layer.shouldRasterize = YES;
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
    
    cell.btnMore.tag = indexPath.row;
    [cell.btnMore addTarget:self action:@selector(onOtherUserVideosMoreButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
    
    cell.btnHideVideo.tag = indexPath.row;
    [cell.btnHideVideo addTarget:self action:@selector(onOtherUserVideoHideButtonClick:) forControlEvents:UIControlEventTouchUpInside];
    
    cell.vwMore.layer.cornerRadius = 3.0f;
    cell.vwHide.layer.cornerRadius = 3.0f;
    cell.vwRemoveOrUnHide.layer.cornerRadius = 3.0f;
    
    if ([arrSelectedIndexPath containsObject:objMyUploadedVideo]) {
        cell.vwHide.hidden = false;
    }
    else {
        cell.vwHide.hidden = true;
    }
    
    if ([[SharedClass objSharedClass] isNightModeEnable]) {
        [cell.btnPlayPause setImage:[UIImage imageNamed:@"playNightMode.png"] forState:UIControlStateNormal];
        [cell.btnPlayPause setImage:[UIImage imageNamed:@"pauseNightMode.png"] forState:UIControlStateSelected];
        cell.vwMainBack.backgroundColor = kNightModeAppThemeColor;
        cell.vwVideoTime.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.7];
        cell.lblVideoDuration.textColor = [UIColor whiteColor];
        cell.lblVideoDescription.textColor = [UIColor whiteColor];
        cell.vwMore.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
        
        [cell.btnHideVideo setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [cell.btnHideVideo setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
        
        [cell.btnMore setImage:[UIImage imageNamed:@"more_icon.png"] forState:UIControlStateNormal];
        [cell.btnMore setImage:[UIImage imageNamed:@"more_icon.png"] forState:UIControlStateSelected];
    }
    else {
        [cell.btnPlayPause setImage:[UIImage imageNamed:@"Play.png"] forState:UIControlStateNormal];
        [cell.btnPlayPause setImage:[UIImage imageNamed:@"pause.png"] forState:UIControlStateSelected];
        cell.vwMainBack.backgroundColor = kTabBarBGColor;
        cell.vwVideoTime.backgroundColor = [[UIColor whiteColor]colorWithAlphaComponent:0.7];
        cell.lblVideoDuration.textColor = kMainGrayColor;
        cell.lblVideoDescription.textColor = kMainGrayColor;
        cell.vwMore.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.7];
        
        [cell.btnHideVideo setTitleColor:kMainGrayColor forState:UIControlStateNormal];
        [cell.btnHideVideo setTitleColor:kMainGrayColor forState:UIControlStateSelected];
        
        [cell.btnMore setImage:[UIImage imageNamed:@"more_icongray.png"] forState:UIControlStateNormal];
        [cell.btnMore setImage:[UIImage imageNamed:@"more_icongray.png"] forState:UIControlStateSelected];
    }
    
    return cell;
}


-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    [self reloadCells:scrollView];
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self reloadCells:scrollView];
}

-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    
}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        [self reloadCells:scrollView];
    }
}

# pragma mark - Video AutoPlay Call Method -

-(void)reloadCells:(UIScrollView *)scrollView {
    CGPoint currentOffset;
    NSTimeInterval currentTime;
    NSTimeInterval timeDiff;
    
    currentOffset = scrollView.contentOffset;
    currentTime = [NSDate timeIntervalSinceReferenceDate];
    timeDiff = currentTime - lastOffsetCapture;
    
    if (timeDiff > 0.1) {
        [self managePlay];
        lastOffset = currentOffset;
        lastOffsetCapture = currentTime;
    }
}

-(void)managePlay {
    [self removeUnWantedCell];
    [self.arrAddedVideo removeAllObjects];
    
    for (FeedSingleViewCell *cell in self.tblVW.visibleCells) {
        [self.arrAddedVideoCell addObject:cell];
        CGRect rectInSuperview;
        CGFloat xPos;
        CGFloat yPos;
        CGPoint imgPoint;
        NSIndexPath *indexPath = [self.tblVW indexPathForCell:cell];
        UserVideoObject *objMyUploadedVideo = [arrOtherVideos objectAtIndex:indexPath.row];
        
        NSString *foo = objMyUploadedVideo.strVideoURL;
        NSString *bar = [foo stringByReplacingOccurrencesOfString:kServer1 withString:kServer2];
        
        rectInSuperview = [cell.playerView convertRect:cell.playerView.frame toView:self.view];
        xPos = self.imgviewCenter.frame.origin.x + self.imgviewCenter.frame.size.width;
        yPos = self.imgviewCenter.frame.origin.y + self.imgviewCenter.frame.size.height;
        imgPoint = CGPointMake(xPos, yPos);
        
        if (CGRectContainsPoint(rectInSuperview, imgPoint)) {
            [currentCell pause];
            [currentCell.loadingIndicatorView removeFromSuperview];
            [currentCell.btnPlayPause setSelected:false];
            [currentCell.seekSlider removeFromSuperview];
            currentCell.playerLayer.sublayers = nil;
            currentCell.player = nil;
            [currentCell unHideVideoControls];
            [self.arrPlayedVideo removeAllObjects];
            
            [self.arrPlayedVideo addObject:bar];
            [self.arrAddedVideo addObject:cell];
            
            [cell hideVideoControls];
            
            // FOR REMOVING OLD VIDEO LAYER
            [cell pause];
            cell.playerLayer.sublayers = nil;
            cell.player = nil;
            
            tempCell = nil;
            tempCell = [[FeedSingleViewCell alloc] init];
            currentCell = cell;
            
            [self callOtherUserVideoViewsAPIInUserVideView:objMyUploadedVideo];
            [cell playVideoInCurrentCell:[NSURL URLWithString:bar]];
            [cell.loadingIndicatorView startAnimating];
        }
        else {
            
        }
    }
}

-(void)removeUnWantedCell {
    for (int i = 0; i < self.arrAddedVideoCell.count; i++) {
        FeedSingleViewCell *cell = [self.arrAddedVideoCell objectAtIndex:i];
        if (cell.isVideoAvailable) {
            // FOR REMOVING OLD VIDEO LAYER
            [cell pause];
            [cell.loadingIndicatorView removeFromSuperview];
            [cell.btnPlayPause setSelected:false];
            [cell.seekSlider removeFromSuperview];
            cell.playerLayer.sublayers = nil;
            cell.player = nil;
            [cell unHideVideoControls];
        }
    }
}

//REMOVE LAST PLAYED VIDEO USING POST NOTIFICATION
-(void)whenFinishOtherUserVideo:(NSNotification *)notification {
    NSDictionary *userInfo = [notification object];
    NSString *strURL = [userInfo valueForKey:@"videoURL"];
    
    // UNHIDE CONTROLLERS AFTER VIDEO FINISHED
    currentCell.seekSlider.value = 0.0f;
    [currentCell unHideVideoControls];
    currentCell.seekSlider.hidden = YES;
    
    // CHECK WHICH VIDEO IS FINISH PLAYING, ONCE WE GOT THAT VIDEO OBJECT MAKE THAT VIDEO CMTIME TO 0, SO IT WILL PLAY FROM START UP POSITING WHEN USER CLICK 2ND TIME ON THAT TO PLAY THIS
    for (int i = 0; i < arrOtherVideos.count; i++) {
        UserVideoObject *objVideo = [arrOtherVideos objectAtIndex:i];
        NSString *strVideoURL = [objVideo.strVideoURL stringByReplacingOccurrencesOfString:kServer1 withString:kServer2];
        if ([strVideoURL isEqualToString:strURL]) {
            objVideo.fVideoLastPauseTime = CMTimeMake(0, 0);
        }
    }
    
    [self.arrPlayedVideo removeObject:strURL];
}

FeedSingleViewCell.m文件视频播放方式

# pragma mark - Initialize Movie Player & Play Current Video -

-(void)playVideoInCurrentCell:(NSURL *)videoURL {
    self.strSelectedVideoURL = [videoURL absoluteString];
    self.loadingIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    self.seekSlider = [[UISlider alloc] init];
    
    
//    AVPlayer *player = [AVPlayer playerWithURL:videoURL];
    
    self.playerItem = [AVPlayerItem playerItemWithURL:videoURL];
    self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
    playerLayer.frame = self.playerView.bounds;
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    
//    self.player = player;
    NSLog(@"PLAYER TAG = %@", self.player);
    self.playerLayer = playerLayer;
    [self.playerView.layer addSublayer:playerLayer];
    [self.playerView bringSubviewToFront:self.btnPlayPause];
    
    [self.btnPlayPause setSelected:true];
    [self.player play];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieFinishedCallback:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
    
    CMTime timeInterval = CMTimeMakeWithSeconds(1.0, 10);
    
    double interval = .1f;
    
    CMTime playerDuration = [self playerItemDuration]; // return player duration.
    if (CMTIME_IS_INVALID(playerDuration)) {
        
    }
    
    double duration = CMTimeGetSeconds(playerDuration);
    if (isfinite(duration)) {
        CGFloat width = CGRectGetWidth([self.seekSlider bounds]);
        interval = 0.5f * duration / width;
    }
    
    __weak typeof(self) weakSelf = self;
    self.timeObserver = [self.player addPeriodicTimeObserverForInterval:timeInterval queue:dispatch_get_main_queue() usingBlock:^(CMTime elapsedTime) {

        [weakSelf observeTime:elapsedTime];
        [weakSelf syncScrubber];
    }];
    
    CGFloat controlsHeight = 30;
    CGFloat controlsY = self.playerView.bounds.size.height - controlsHeight;
    self.seekSlider.frame = CGRectMake(5, controlsY, self.playerView.bounds.size.width - 10, controlsHeight);
    self.loadingIndicatorView.center = self.playerView.center;
    
    [self.playerView addSubview:self.seekSlider];
    [self.seekSlider addTarget:self action:@selector(sliderBeganTracking:) forControlEvents:UIControlEventTouchDown];
    [self.seekSlider addTarget:self action:@selector(sliderEndedTracking:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
    [self.seekSlider addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged];
    
    self.loadingIndicatorView.hidesWhenStopped = true;
    [self.playerView addSubview:self.loadingIndicatorView];
    
    [self.playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:playbackLikelyToKeepUpContext];
    [self.playerItem addObserver:self forKeyPath:@"rate" options:0 context:0];
}

我在这里上传我的完整代码。

崩溃的原因是什么?

enter image description here

最佳答案

看起来您需要将以下代码添加到您的 View Controller 类中:

- (void)dealloc {
    currentCell = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

还要确保将 currentCell 声明为强或弱。

关于ios - 离开 UIViewController 时应用程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44772546/

相关文章:

ios - 如何修复 libCordova.a(CDVLogger.o) ld : 2 duplicate symbols for architecture x86_64 on mac os ionic 3 app?

ios - AVAsset 无法使用本地音频文件播放

uitableview - 在iOS5 Storyboard上将具有静态和动态内容的UITableView分组

ios - 在 UIView 上上下滑动工作但 ScrollView 阻碍它快速?

ios - 滚动所有 tableviewcell 内的所有 CollectionViewCell

ios - 在 UITableViewCell 中播放视频的最佳方式是什么

ios - 播放/暂停下一个/上一个按钮在控制中心显示为灰色

android - 如何使用 react-native 在 textInput 字段中自动获取 '/'(斜线)

objective-c - __bridge_transfer 的描述相互矛盾;它避免双重保留吗?

ios - SWIFT iOS 中未调用委托(delegate)