iOS AVPlayer 释放时无法完全释放内存,如何解决?

crazymoon
  • 5
新手上路,请多包涵

1.问题描述:
在ARC机制下,我需要做一个测试视频的软件。有用到3个方法,设置播放源方法A,在方法A中给创建的AVPlayerItem添加kvo方法B,在kvo方法B中判断视频状态,当数量达到并调用上报方法C,如未达到,则继续调用方法A。方法C上报结束后,继续调用方法A,如此循环。结果方法A中的player,playerItem,playerLayer,内存一直慢慢增大。

2.方法代码

方法A

-(void)CheckVideoURlCanPlay{
    @autoreleasepool {
        //发送检测视频播放可用性进度通知
        NSDictionary *dict = @{@"type":@"checktraversalvideo",@"total":@(0),@"progress":@(self.needCheckArr.count)};
        [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"startcheckvideourl" object:nil userInfo:dict]];
        
        @autoreleasepool {
            if (self.needCheckArr == nil) {
                self.needCheckArr = [VideoURLDataBase selectAllData];
            }
            
            if (self.needCheckArr.count == 0) {
                isCheckOver = YES;
                //NSLog(@"检查视频可播放性结束");
                [self uploadVideoPlayResult:uploadArr isLast:1];
                self.player = nil;
                return;
            }
                        
            if (_playItem != nil) {
                [self.playItem removeObserver:self forKeyPath:@"status"];
                self.playItem = nil;
                self.player = nil;
                [self.playLayer removeFromSuperlayer];
                self.playLayer = nil;
            }
                        
            VideoPlayDataObj *videoPlay = [self.needCheckArr objectAtIndex:0];
            NSURL *url = [NSURL URLWithString:videoPlay.videoURL];
            _player = [AVPlayer playerWithURL:url];
            _playLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
            _playLayer.videoGravity = AVLayerVideoGravityResizeAspect;
            _playLayer.frame=CGRectMake(0, 80, 1, 1);
            [self.view.layer addSublayer:self.playLayer];
            [self.player play];
            videoPlay = nil;
        }
    [_player.currentItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionOld context:@"checkVideoCanPlay"];// 监听status属性
    }
}

方法B

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    @autoreleasepool {
        if ([keyPath isEqualToString:@"status"] && context == @"checkVideoCanPlay") {
            AVPlayerItem *item = (AVPlayerItem *)object;

            @autoreleasepool {
                if ([item status] == AVPlayerStatusReadyToPlay) {
                    // NSLog(@"准备播放");
                    [self.player pause];
                            
                    //VideoPlayDataObj *videoPlay = [VideoURLDataBase selectFirstData];
                    VideoPlayDataObj *videoPlay = [self.needCheckArr objectAtIndex:0];
                            
                    if (videoPlay == nil) {//数据库中数据取完,则上传,然后跳出
                        [self uploadVideoPlayResult:uploadArr isLast:1];
                        return;
                    }
                    
                    if (uploadArr == nil) {
                        uploadArr = [NSMutableArray array];
                    }
                    
                    if (uploadArr.count<20){//上报结果数量
                        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                        [dict setObject:[defaults objectForKey:@"registerId"] forKey:@"agentid"];
                        [dict setObject:[NSString stringWithFormat:@"IOS %@", [[UIDevice currentDevice] systemVersion]] forKey:@"androidVersion"];
                        [dict setObject:@"" forKey:@"apkVersion"];
                        [dict setObject:@"0" forKey:@"buffertime"];
                        [dict setObject:@"4GIOS" forKey:@"categoryName"];
                        [dict setObject:@"120" forKey:@"categoryid"];

                        if(videoPlay.channelid == 0 ){
                            [dict setObject:@"0" forKey:@"channel"];
                        }else{
                            [dict setObject:videoPlay.channelid forKey:@"channel"];
                        }
        
                        [dict setObject:@"-40" forKey:@"dbm"];
                        [dict setObject:@"请求成功" forKey:@"description"];
                        [dict setObject:@"0" forKey:@"downspeed"];
                        [dict setObject:@"0" forKey:@"duration"];
                        [dict setObject:@"0" forKey:@"id"];
                        [dict setObject:@"0" forKey:@"islive"];
                        [dict setObject:isWifi forKey:@"nettype"];
                        [dict setObject:@"0" forKey:@"pchannel"];
                        [dict setObject:@"0" forKey:@"result"];
                        [dict setObject:@"0" forKey:@"resultCode"];
                        [dict setObject:[RequestUtils deviceVersion] forKey:@"terminal"];
                        [dict setObject:videoPlay.title forKey:@"testData"];
                        [dict setObject:[defaults objectForKey:@"username"] forKey:@"testMobile"];
                        [dict setObject:videoPlay.moviePath forKey:@"testModel"];
                        [dict setObject:[RequestUtils getTestTime] forKey:@"testTime"];
                        [dict setObject:@"6007" forKey:@"testfunid"];
                        [dict setObject:videoPlay.videoURL forKey:@"url"];
                        
                        [uploadArr addObject:dict];
                    }else{
                        [self uploadVideoPlayResult:uploadArr isLast:0];
                        return;//跳出方法,等待上传完毕,发送通知,重新调用CheckVideoURlCanPlay
                    }
                    videoPlay = nil;
                } else if ([item status] == AVPlayerStatusFailed) {
                    // NSLog(@"播放失败");
                    [self.player pause];
                    // VideoPlayDataObj *videoPlay = [VideoURLDataBase selectFirstData];
                    VideoPlayDataObj *videoPlay = [self.needCheckArr objectAtIndex:0];
                    [FailedURLDataBase insertIntoNewData:videoPlay.videoURL];
                            
                    if (videoPlay == nil) {
                        [self uploadVideoPlayResult:uploadArr isLast:1];
                        return;
                    }
                    
                    if (uploadArr ==nil) {
                        uploadArr = [NSMutableArray array];
                    }
                    
                    if (uploadArr.count<20){
                        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
                        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
                        [dict setObject:[defaults objectForKey:@"registerId"] forKey:@"agentid"];
                        [dict setObject:[NSString stringWithFormat:@"IOS %@", [[UIDevice currentDevice] systemVersion]] forKey:@"androidVersion"];
                        [dict setObject:@"" forKey:@"apkVersion"];
                        [dict setObject:@"0" forKey:@"buffertime"];
                        [dict setObject:@"4GIOS" forKey:@"categoryName"];
                        [dict setObject:@"120" forKey:@"categoryid"];

                        if(videoPlay.channelid ==0){
                            [dict setObject:@"0" forKey:@"channel"];
                        }else{
                            [dict setObject:videoPlay.channelid forKey:@"channel"];
                        }

                        [dict setObject:@"-40" forKey:@"dbm"];
                        [dict setObject:@"请求失败" forKey:@"description"];
                        [dict setObject:@"0" forKey:@"downspeed"];
                        [dict setObject:@"0" forKey:@"duration"];
                        [dict setObject:@"0" forKey:@"id"];
                        [dict setObject:@"0" forKey:@"islive"];
                        [dict setObject:isWifi forKey:@"nettype"];
                        [dict setObject:@"0" forKey:@"pchannel"];
                        [dict setObject:@"1" forKey:@"result"];
                        [dict setObject:@"0" forKey:@"resultCode"];
                        [dict setObject:[RequestUtils deviceVersion] forKey:@"terminal"];
                        [dict setObject:videoPlay.title forKey:@"testData"];
                        [dict setObject:[defaults objectForKey:@"username"] forKey:@"testMobile"];
                        [dict setObject:videoPlay.moviePath forKey:@"testModel"];
                        [dict setObject:[RequestUtils getTestTime] forKey:@"testTime"];
                        [dict setObject:@"6007" forKey:@"testfunid"];
                        [dict setObject:videoPlay.videoURL forKey:@"url"];
                        
                        [uploadArr addObject:dict];
                    }else{
                        [self uploadVideoPlayResult:uploadArr isLast:0];
                        return;//跳出方法,等待上传完毕,发送通知,重新调用CheckVideoURlCanPlay
                    }
                    videoPlay = nil;
                }
                [NSThread sleepForTimeInterval:0.5];
                [self.player.currentItem.asset cancelLoading];
                [self.player.currentItem cancelPendingSeeks];
                if (self.player.currentItem != nil) {
                    [self.player.currentItem removeObserver:self forKeyPath:@"status"];
                    _player = nil;
                    [_playLayer removeFromSuperlayer];
                    _playLayer = nil;
                }
                [self.needCheckArr removeObjectAtIndex:0];
                [self CheckVideoURlCanPlay];
            }//释放池括号
        }
    }
}
回复
阅读 9.1k
3 个回答

退出的时候 _player.currentItem removeObserver,再看看block那有没有环

打滚的桔子
  • 0
新手上路,请多包涵

对象没释放吧,开内存分析看看。

[player.currentItem cancelPendingSeeks];
[player.currentItem.asset cancelLoading];

加这两行代码,将正在播放的 item 释放掉

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏