Accessors / Getters and Lazy Initialization
I have a question about overriding auto-generated accessor methods. The following would not work (I believe) because each getter references the other getter. Is there a rule that accessor methods should not use other accessor methods, or do you just have to watch out for these situations individually?
-(UIImage *) image{
if(image == nil){
if(self.data == nil){
[self performSelectorInBackground: @selector(loadImage) withObject: nil]
}else{
self.image = [UIImage imageWithData: self.data];
}
}
return image;
}
-(NSData *) data {
if(data == nil){
if(self.image == nil){
[self performSelectorInBackground: @selector(loadData) withObject: nil]
}else{
self.data = UIImageJPEGRepresentation(self.image, 0.85);
}
}
return data;
}
I have to emphasize that the image use presented here is an example, and thoughts concerning what to do in this particular example are less important than in the gen开发者_运维问答eral case.
First, don’t be too smart for your own good. If you want to get over some bottleneck, first measure and make sure it’s really there. I believe that both UIImage
and NSData
do some internal lazy loading, so that your code might be essentially useless. Second, even if you really wanted to do something like that by hand, try splitting the caching code into a separate class, so that you don’t pollute the code of the main class.
There is no rule about accessors (at least no that I know of), because people don’t do much lazy loading in accessors. Sometimes I get myself caught by an endless loop caused by lazy [UIViewController loadView]
in combination with [UIViewController view]
, but that’s about it.
There's nothing that forbids it, but you're definitely writing some confusing code. Essentially, these two properties have a circular dependency. This is hard to both read and debug. It's not clear why you'd want to "load the data" before you "load the image", or why you'd also want to support "loading the image" before you "load the data", or really how the two properties are really two different things.
what you're actually doing in this example could take a long time to load; it is best to ensure that it is thread safe.
furthermore, it would be even better if you made the data object a real data provider (typically using protocols), separate from the class, and to make the image container expose that it is handling a lazily loaded object (which may cause outcry from some people).
specifically, you may want to invoke a load data/image from the provider, call it from awakeFromNib (for example) - then the loader runs off and loads the data on a secondary thread (esp. if downloaded). give the data provider a callback to inform the view that the image is ready (typically using protocols). once the view takes the unarchived image, invalidate the data provider.
finally, if you're dealing with app resources, the 'system' will cache some of this for you sooo you'd be attempting to work against what's already optimised behind the scenes.
in short, it's usually ok (e.g. not lazy initialization) - but this specific design (as another poster said) has a circular dependency which should be minimized.
精彩评论