我的代码(特别是当我进入TDD时)有很多延迟加载的属性,例如:
@interface MyClass ()
@property (nonatomic, strong) MyFoo *myFoo;
@end
@implementation MyClass
- (MyFoo *)myFoo {
if (!_myFoo) {
_myFoo = [MyFoo alloc] sharedFoo]; // or initWithBar:CONST_DEF_BAR or whatever
}
return _myFoo;
}
@end
或者,更好的,线程安全的版本:
- (MyFoo *)myFoo {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_storeHelper = [SHStoreHelper sharedStoreHelper];
});
}
我希望Apple能够使这个属性的一个方面符合自动代码生成的条件,例如:
@property (lazyload) MyFoo *myFoo;
但是,除此之外,我想为实现位设置一个宏,比如
#define LAZY_ALLOC(x, y, _y, a, i) -(x *)y { if (!_y) { _y = [[x a] i]; } return _y }
然后代替常规方法实现
LAZY_ALLOC(MyClass, myClass, _myClass, alloc, init)
对于想要
的类来说足够灵活LAZY_ALLOC(OtherClass, otherClass, _otherClass, sharedClass, nil)
或
LAZY_ALLOC(OtherClass, otherClass, _otherClass, alloc, initWithFrame:SOME_FRAME)
1)预处理器需要_y。有没有办法让它构建_autosynthesized ivar而不分别传递它? 2)这有什么大问题吗?对我而言,它增强了可读性,因为它实质上比完全写出的版本更快地说“哦那件事” 3)你觉得它风格狡猾吗?风格迥异?
答案 0 :(得分:3)
我认为你想要的是##
。你可以把它写成:
#define LAZY_ALLOC(type, name, initialValue) \
-(type *)name { \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
if (! _ ## name) { \
_ ## name = (initialValue); \
} \
} \
return _ ## name; \
}
要清楚,我不会在单例的sharedInstance
- 类型方法之外使用这个特定的习惯用于延迟加载。由于静态dispatch_once_t,此代码仅对每个类(不是每个实例)执行延迟加载。我只是将代码复制出来并将其转换为宏模板以说明该技术,但我觉得我应该澄清一下。
就个人而言,对于延迟加载普通实例变量,我会使用非线程安全版本,只需切换到急切加载或专门处理案例,如果你需要线程安全。有一些技术可以在访问器中组合延迟加载和线程安全,但是:
它们相当慢。
很难同时真正需要两者。
除了在你的访问器方法中粘贴互斥锁之外,你可能不得不为线程安全做一些特殊的架构。
所以我不会将这种情况纳入标准模板宏。
答案 1 :(得分:0)
编写方法+(id) lazyLoad:(Class)class sharedPointer:(NSObject**)ptrAddr
或其他类似方法。使它成为LazyLoader类的一个方法,它只实现这个方法。
使用它:
- (MyFoo *)myFoo {
return [LazyLoader lazyLoad:[MyFoo class] sharedPointer:&_myFoo];
}
在sharedPointer parm上可能需要一些ARC甜味剂,但基本上它应该可以使用,并且可以根据您的意愿制作线程安全(如果您愿意)。
(我将把它作为练习让读者弄清楚如何进行备用init方法。)