2014-09-27 29 views
2

我有一些对象,更准确地说是模型,它们的某些属性被延迟加载,即在读取时从服务器获取。目前,我运用经典技术,例如Objective-C:惰性加载的模型模式

@synthetize description = _description; 
- (NSString *)description { 
    if (!_description) { 
     NSError *error = nil; 
     _description = [NSString stringWithContentsOfURL:url 
           encoding:NSUTF8StringEncoding 
           error:&error]; 
     if (error) { 
      _description = nil; 
      // error handling 
     } 
    } 
    return _description; 
} 

但是,它涉及很多代码重复。当然,我仍然可以有一个通用的方法来做这件事,并在所有的getter中调用这个方法(这就是我所做的)。但你有更好的主意吗?

编辑:使注释中所建议的代码更安全。这里是另一个建议:

@synthesis description = _description; 
- (NSString *)descriptionWithCompletion:(void (^)(NSString *description, NSError *error))completion { 
    if (!_description) { 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      NSError *error = nil; 
      _description = [NSString stringWithContentsOfURL:url 
            encoding:NSUTF8StringEncoding 
            error:&error]; 
      if (error) _description = nil; 

      completion(_description, error); 

     }); 
    } 
    completion(_description, nil); 
} 
+0

这不是一个好的模式!您的调用者无法处理由此产生的错误,并且在网络访问完成之前阻止调用线程。这是一个非常好的方式来让用户界面口吃,并让你的应用被操作系统杀死。您可能想要向模型的用户指示访问这些值的过程是异步的,并且可能会因为它们传递给您一个完成块(它带有一个可选错误)而失败。 – 2014-09-27 14:32:55

+0

所以,你建议让用户把一个完成块传给getter。然后,在后台队列中分派获取进程,后台队列将以对象和错误为参数调用完成块。我对吗? – user1553136 2014-09-27 14:43:51

+0

是的,确切地说。但是,这对调用者来说有些痛苦,所以如果可能的话,您可能希望减少这些异步方法的数量,例如通过一次加载整个模型。 – 2014-09-27 14:49:32

回答

0

所以,你想减少的方法是这样的样板:

- (NSString *)prop {return [self _genericGetterForProperty:_prop];} 

使用宏是一种选择;它会减少文本的数量,但是您仍然需要每种方法的一行,所以我不清楚这是否真的值得额外的复杂性。

有一种方法可以通过dynamic method resolution来做到这一点。基本上,你在你的班上实施+ resolveInstanceMethod:。如果有人试图调用您的模型对象上的一个方法,而这个方法在编译时并未提供,则会调用它。你可以实现它来检查选择器是否与你的xxxWithCompletion:结构匹配。如果是这样,您可以基于“xxx”值构建实现并将其添加到您的课程中。你可以通过声明你的属性为@dynamic或通过显式地通过pragmas禁止警告来阻止编译器警告你。不过,我不推荐它。这是一个复杂而棘手的解决方案;除非你有数百个这些属性,否则我只会写样板文件。 (或写一个脚本来写样板文件。)