AVAsset loadValuesAsynchronouslyForKeys:completionHandler 从不执行

Posted

技术标签:

【中文标题】AVAsset loadValuesAsynchronouslyForKeys:completionHandler 从不执行【英文标题】:AVAsset loadValuesAsynchronouslyForKeys:completionHandler never executes 【发布时间】:2018-02-10 05:27:36 【问题描述】:

这个问题已经在这里问了好几次了,但我仍然没有在任何地方看到任何答案。这已经杀死了我几个小时,我希望在这里得到一些帮助。我有以下代码:

NSURL *url = [NSURL URLWithString:sourceVideoName];
NSDictionary *options = @ AVURLAssetPreferPreciseDurationAndTimingKey: @YES ;

PHFetchResult *ph_fetch = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
PHAsset *ph_asset = [ph_fetch firstObject];

RCTLogInfo(@"Now we have PHAsset:\n%@", ph_asset);

[[PHImageManager defaultManager] requestAVAssetForVideo:ph_asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) 

  RCTLogInfo(@"Now we have AVAsset:\n%@", asset);

  NSError *error = nil;
  AVKeyValueStatus tracksStatus = [asset statusOfValueForKey:@"tracks" error:&error];

  switch (tracksStatus) 
    case AVKeyValueStatusCancelled:
      [self log:@"Early Tracks Canceled"];
      break;
    case AVKeyValueStatusLoading:
      [self log:@"Early Tracks Loading"];
      break;
    case AVKeyValueStatusLoaded:
      [self log:@"Early Tracks Loaded"];
      break;
    case AVKeyValueStatusFailed:
      [self log:@"Early Tracks Failed"];
      break;
    case AVKeyValueStatusUnknown:
      [self log:@"Early Tracks Unknown"];
      break;
  

  [asset loadValuesAsynchronouslyForKeys:@[@"tracks", @"duration"] completionHandler:^() 
    RCTLogInfo(@"We finally have a track callback???");
  ];

];

当然,我们从来没有真正执行过最终的回调。我不知道为什么,也不知道如何解决它。

【问题讨论】:

这可能是 ARC 问题。 【参考方案1】:

对我的问题的评论让我深入了解了答案。基本版本是,在回调执行之前,asset 似乎已从内存中释放。

ARC 为属性提供了更强的内存保留,因此可以通过在标头中添加接口定义来实现:

@property AVAsset *asset;
@property PHAsset *photoAsset;

并将上述问题中的代码转换为:

NSURL *url = [NSURL URLWithString:sourceVideoName];
NSDictionary *options = @ AVURLAssetPreferPreciseDurationAndTimingKey: @YES ;

PHFetchResult *ph_fetch = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
[self setPhotoAsset:[ph_fetch firstObject]];

RCTLogInfo(@"Now we have instance PHAsset:\n%@", [self photoAsset]);

[[PHImageManager defaultManager] requestAVAssetForVideo:[self photoAsset] options:nil resultHandler:^(AVAsset * _Nullable localAsset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) 

  RCTLogInfo(@"Now we have local AVAsset:\n%@", localAsset);
  [self setAsset:localAsset];
  RCTLogInfo(@"Now we have instance AVAsset:\n%@", [self asset  ]);

  NSError *error = nil;
  AVKeyValueStatus tracksStatus = [[self asset] statusOfValueForKey:@"tracks" error:&error];

  switch (tracksStatus) 
    case AVKeyValueStatusCancelled:
      [self log:@"Early Tracks Canceled"];
      break;
    case AVKeyValueStatusLoading:
      [self log:@"Early Tracks Loading"];
      break;
    case AVKeyValueStatusLoaded:
      [self log:@"Early Tracks Loaded"];
      break;
    case AVKeyValueStatusFailed:
      [self log:@"Early Tracks Failed"];
      break;
    case AVKeyValueStatusUnknown:
      [self log:@"Early Tracks Unknown"];
      break;
  

  [[self asset] loadValuesAsynchronouslyForKeys:@[@"tracks", @"duration"] completionHandler:^() 
    RCTLogInfo(@"We finally have a track callback!!!");
  ];

];

【讨论】:

以上是关于AVAsset loadValuesAsynchronouslyForKeys:completionHandler 从不执行的主要内容,如果未能解决你的问题,请参考以下文章

AVAsset "tracksWithMediaType" 返回一个空数组

为啥 AVAsset 轨道对于同一个视频文件有不同的 timeRange?

UIActivity 和 AVAsset 数据类型使用

将AVAsset视频文件拆分为块

AVAsset 的 NaturalSize 与视频文件不同

请求 AVAsset 时维护顺序