Objective c 目标C:延迟加载模型模式

Objective c 目标C:延迟加载模型模式,objective-c,design-patterns,Objective C,Design Patterns,我有对象,更准确地说是模型,其中的一些属性是惰性加载的,即从服务器读取的。目前,我采用了经典的技巧,例如 @synthetize description = _description; - (NSString *)description { if (!_description) { NSError *error = nil; _description = [NSString stringWithContentsOfURL:url

我有对象,更准确地说是模型,其中的一些属性是惰性加载的,即从服务器读取的。目前,我采用了经典的技巧,例如

@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);
}

因此,您正试图简化以下方法的样板:

- (NSString *)prop {return [self _genericGetterForProperty:_prop];}
使用宏是一种选择;这将减少文本的数量,但是每个方法仍然需要一行,所以我不清楚这是否值得额外的复杂性

有一种方法你可以通过。本质上,您在类上实现了
+resolveInstanceMethod:
。如果有人试图调用您在编译时未提供的模型对象上的方法,则会调用该方法。您可以实现它来检查传递的选择器,查看它是否与您的
xxxWithCompletion:
结构匹配。如果有,您可以基于“xxx”值构建一个实现,并将其添加到您的类中。您可以通过将属性声明为
@dynamic
或通过pragmas显式抑制警告来防止编译器对此发出警告


不过我不推荐。这是一个复杂而棘手的解决方案;除非你有成百上千个这样的属性,否则我就写一个样板。(或编写脚本来编写样板文件。)

这不是一个好模式!您的调用者无法处理由此产生的错误,您正在阻止调用线程,直到网络访问完成。这是一个很好的方法,让用户界面结巴,让你的应用程序被操作系统杀死。相反,您可能希望向模型的用户指示,访问这些值是异步的,并且可能会失败,方法是让它们向您传递一个完成块(这会导致可选错误)。因此,您建议让用户向getter传递一个完成块。然后,在后台队列中调度抓取过程,该队列将使用对象和错误作为参数调用完成块。我说得对吗?是的,没错。不过,这对调用者来说有点痛苦,因此如果可能的话,您可能希望减少这些异步方法的数量,比如一次加载整个模型。嗯,除了通过声明getter并避免所有的
-(NSString*)属性{return[self-genericGetterForProperty:_-prop];}
之外,你知道如何限制代码重复吗。