Reputation: 645
My App Crash while leaving UIViewController
with following error.
[FeedSingleViewCell retain]: message sent to deallocated instance 0x7ffbb8950a00
in My UIViewController
, I used UITableView
and there's AutoPlay Functionality, when video finish or when user leave Current UIViewController
, in ViewWillDisAppear
I make AVPlayer
nil, Remove AVPlayer
SubLayers, but still it getting crashed.
Sample Code
- (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 file Video Playing Method
# 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];
}
Here I upload my full code.
What's the reason for crash?
Upvotes: 0
Views: 383
Reputation: 8322
You need to add or change in your tableViewCell's class.
This crash may be happened due to your observer still exist . so you need to remove manually.
-(void)dealloc {
@try {
[self.playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
[self.playerItem removeObserver:self forKeyPath:@"rate"];
self.playerItem = nil;
}@catch(id anException) {
NSLog(@"Trending Video Remove Observer Exception = %@", anException);
}
}
Upvotes: 1
Reputation: 539
Try with removing delegate property like below.
-(void) viewWillDisappear:(BOOL) animated
{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController])
{
if (self.navigationController.interactivePopGestureRecognizer.delegate == self)
{
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}
}
Upvotes: 0
Reputation: 1245
Looks like you need to add the following code to your view controller class:
- (void)dealloc {
currentCell = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Also make sure that currentCell is declared as strong or weak.
Upvotes: 3