generateCGImagesAsynchronouslyForTimes in ARC

2019-04-10 14:59发布

If I run the following in a project where ARC is enabled the completion handler never fires. But without ARC it works as expected. What am I missing here?

NSURL *url = [NSURL URLWithString:@"http://media.w3.org/2010/05/sintel/trailer.mp4"];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
CMTime thumbTime = CMTimeMakeWithSeconds(5,30);

AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, 
                                                   CGImageRef im, 
                                                   CMTime actualTime, 
                                                   AVAssetImageGeneratorResult result, 
                                                   NSError *error){
    NSLog(@"completion handler");
};

generator.maximumSize = CGSizeMake(320, 180);
[generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];

3条回答
Evening l夕情丶
2楼-- · 2019-04-10 15:43

Looks like generateCGImagesAsynchronouslyForTimes does not retain the generator. Make generator a member variable of your instance and assign to it. As soon as I did that, it started working. The code will look something like this:

NSURL *url = [NSURL URLWithString:@"http://media.w3.org/2010/05/sintel/trailer.mp4"];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
[generator_ cancelAllCGImageGeneration];
generator_ = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator_.appliesPreferredTrackTransform = YES;
CMTime thumbTime = CMTimeMakeWithSeconds(5,30);

AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, 
                                                   CGImageRef im, 
                                                   CMTime actualTime, 
                                                   AVAssetImageGeneratorResult result, 
                                                   NSError *error){
    NSLog(@"completion handler");
};

generator_.maximumSize = CGSizeMake(320, 180);
[generator_ generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
查看更多
Emotional °昔
3楼-- · 2019-04-10 15:47

The image generator definitely does not get retained by the framework. Not sure how often Apple Programming Guide gets updated, but you can read that in AV Foundation Prog. Guide, in Generating a Sequence of Images quite clearly:

In addition, you must ensure that you retain the image generator until it has finished creating the images.

查看更多
The star\"
4楼-- · 2019-04-10 15:55

Based on Michael pointing out that generator doesn't get retained, if you simply 'use' the generator var inside the completion block, everything will work.

So I guess the answer is...

NSURL *url = [NSURL URLWithString:@"http://media.w3.org/2010/05/sintel/trailer.mp4"];
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
CMTime thumbTime = CMTimeMakeWithSeconds(5,30);

AVAssetImageGeneratorCompletionHandler handler = ^(CMTime requestedTime, 
                                                   CGImageRef im, 
                                                   CMTime actualTime, 
                                                   AVAssetImageGeneratorResult result, 
                                                   NSError *error){
    NSLog(@"make sure generator is used in this block and it'll work %@", generator);
};

generator.maximumSize = CGSizeMake(320, 180);
[generator generateCGImagesAsynchronouslyForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:thumbTime]] completionHandler:handler];
查看更多
登录 后发表回答