【问题标题】:How to wait for delegate method execution before return statement?如何在返回语句之前等待委托方法执行?
【发布时间】:2016-03-08 16:53:35
【问题描述】:

我有一个模型对象,它有一个类方法来检查模型对象是否已经存在,如果存在则返回它,或者如果不存在则创建它然后返回它。此类使用 VLC 框架来生成有关视频文件的数据并生成缩略图。这就是我遇到麻烦的地方。

一旦调用了fetchthumbnail 方法,VLCThumbnailer 就会通过委托方法返回缩略图。问题是,在我的类创建方法到达它的返回函数之后,委托方法才会返回。这是一个代码示例。

-(AnimuProfile*)createnewProfileforFilename:(NSString*)filename{

        NSURL *fileURL = [NSURL fileURLWithPath:filename];
    VLCMedia *media = [VLCMedia mediaWithURL:fileURL];
    FilenameParser *parser = [[FilenameParser alloc]init];
    NSArray *parsedFilename = [parser parseFilename:[filename lastPathComponent]];

    NSArray *mediaArray = [media tracksInformation];
    if (mediaArray.count != 0) {
        NSDictionary *videoTrackinfo = [mediaArray objectAtIndex:0];
        _fansubGroup = parsedFilename[0];
        _seriesTitle = parsedFilename[1];
        _episodeNumber = parsedFilename[2];
        _filename = [filename lastPathComponent];
        _filepathURL = fileURL;
        _filepathString = filename;
        _watched = NO;
        _progress = [VLCTime timeWithInt:0];
        _length = [[media length]stringValue];

        NSNumber *resolution = [videoTrackinfo valueForKey:@"height"];
        _resolution = [NSString stringWithFormat:@"%@p",resolution];

        VLCMediaThumbnailer *thumbnailer = [VLCMediaThumbnailer thumbnailerWithMedia:media andDelegate:self];

        [thumbnailer fetchThumbnail];



    NSString *libPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    NSString *profileName = [[_filename lastPathComponent] stringByAppendingPathExtension:@"prf"];
    NSString *pathandProfileName = [libPath stringByAppendingPathComponent:profileName];
    [NSKeyedArchiver archiveRootObject:self toFile:pathandProfileName];

      return self;
}

然后是委托方法:

#pragma mark VLC Thumbnailer delegate methods
- (void)mediaThumbnailerDidTimeOut:(VLCMediaThumbnailer *)mediaThumbnailerP{
    NSLog(@"Thumbnailer timed out on file %@",_filename);
    UIImage *filmstrip = [UIImage imageNamed:@"filmstrip"];
    _thumbnail = UIImagePNGRepresentation(filmstrip);
}
- (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail{
    UIImage *image = [UIImage imageWithCGImage:thumbnail];
    _thumbnail = UIImagePNGRepresentation(image);

}

我知道锁定主线程等待调用委托方法是不可行的,那么在这种情况下应该怎么做?

【问题讨论】:

标签: ios objective-c multithreading delegates vlc


【解决方案1】:

我知道锁定等待委托的主线程是不可行的 方法被调用,那么在这种情况下应该怎么做?

这些委托方法在 VLC 的视频处理线程上被调用。它们不是主线程,因此,您不应该直接在返回块中调用随机 UIKit API。

您需要在结果可用时对其进行处理。如果 VLC 是使用现代模式实现的,它将使用完成块。但事实并非如此,所以......

 - (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail{
  {
      dispatch_async(dispatch_get_main_queue(), ^{ ... process thumbnail and update UI accordingly here ...});
  }

也就是说,您的createnewProfileforFilename: 方法应该开始处理,但不要指望它在稍后的某个时间完成。然后,当稍后发生这种情况时,您会使用在后台处理的数据触发 UI 更新。

而且,正如您所说,您永远不应该阻塞主队列/线程。

【讨论】:

  • 谢谢。看来您对 VLC 的工作原理有所了解。问题是我不是从视图控制器调用这些方法,而是从模型对象本身调用这些方法。这是一个棘手的问题。
  • @JosephToronto 仅与我阅读的该课程的来源一样多。 :) 仍然不太棘手;您的模型将分派到主线程,并且主线程更新方法将(很可能)告诉控制器层有新数据可用,然后控制器层可以处理 UI 层的问题。或者,您可以触发通知,但这似乎有点矫枉过正,而且更难调试(“现在,该通知是从哪里来的?!”)。
【解决方案2】:

我能够通过创建一个单独的类作为代理来解决它,发出缩略图获取请求然后处理它们。

@property NSMutableArray *queue;
@end

@implementation ThumbnailWaiter

+(id)sharedThumbnailWaiter{
    static ThumbnailWaiter *singletonInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        singletonInstance = [[self alloc] init];
    });
    return singletonInstance;
}


-(id)init{
    self = [super init];
    if (self) {


        NSMutableArray *queue = [NSMutableArray array];
        _queue = queue;


    }


    return self;
}


-(void)requestThumbnailForProfile:(AnimuProfile*)profile{


    VLCMedia *media = [VLCMedia mediaWithURL:profile.filepathURL];
    VLCMediaThumbnailer *thumbnailer = [VLCMediaThumbnailer thumbnailerWithMedia:media andDelegate:self];
    [_queue addObject:profile];
    [thumbnailer fetchThumbnail];

}




#pragma mark VLC Thumbnailer delegate methods
- (void)mediaThumbnailerDidTimeOut:(VLCMediaThumbnailer *)mediaThumbnailerP{


}

- (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail{
    UIImage *image = [UIImage imageWithCGImage:thumbnail];
    AnimuProfile *profile = _queue.firstObject;
    profile.thumbnail = UIImagePNGRepresentation(image);
    [profile saveProfile];
    [_queue removeObjectAtIndex:0];

   }

必须以这种方式这样做似乎几乎是愚蠢的,但它似乎正在工作。

【讨论】:

  • 我最终通过 NSOperations & Blocks 做到了这一点。您也应该看看这种方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多