Reputation: 1220
I am working on a UITableViewController
@interface GinkgoDeliveryOrdersTableViewController : UITableViewController
@property PFQuery * query;
@property NSArray * products;
@end
How shall I initialize these two properties? Currently, I am doing lazy initialization:
@implementation GinkgoDeliveryOrdersTableViewController
@synthesize query = _query;
@synthesize products = _products;
- (void) initQuery {
_query = [PFQuery queryWithClassName:@"_Product"];
}
- (void) initProducts {
if(! _query)
[self initQuery];
_products = [_query findObjects];
}
As a result, every time I want to use these two properties, I have to do something like this:
if(! self.products)
[self initProducts];
and
if(! self.query)
[self initQuery];
I feel I am doing something wrong here. Is there a cleaner way to do this? Thank you very much!
Upvotes: 5
Views: 8150
Reputation: 8322
When you create a @property
the compiler creates setters and getters for you automatically.
// Let's say you create a public property in your header file (.h)
@property NSObject *var;
// You synthesize your property in your implementation file (.m)
@synthesize var = _var;
// What does the compiler creates for you?
// A getter that by default has the same name as your variable
- (NSObject *)var
{
return _var;
}
// A setter that by default is called "set" + "Var" (your variable name with first letter in uppercase)
- (void)setVar:(NSObject *)var
{
_var = var;
}
Lazy instantiation is a design pattern where you chose to wait until the very last moment to instantiate your objects. So, in your case, it would be in the getter
. When someone tries to read a property that was not yet used it is time to instantiate them :D
This is what I think you want :D
// GinkgoDeliveryOrdersTableViewController.h
@interface GinkgoDeliveryOrdersTableViewController : UITableViewController
@property PFQuery *query;
@property NSArray *products;
@end
// GinkgoDeliveryOrdersTableViewController.m
@implementation GinkgoDeliveryOrdersTableViewController
@synthesize query = _query;
@synthesize products = _products;
// SETTERS
- (void)setQuery:(PFQuery *)query {
_query = query;
}
- (void)setQuery:(NSArray *)products {
_products = array;
}
// GETTERS
- (PFQuery *)query {
if (!_query)
_query = [PFQuery queryWithClassName:@"_Product"];
return _query;
}
- (NSArray *)products {
if (!_products)
_products = [_query findObjects];
return _products;
}
@synthesize
for primitive types allocates the space required for the variable.@synthesize
for pointers to objects allocates the space required for the pointer only. You have to allocate and initialize your property._var
outside of setters and getters. Use self.var instead.@property (nonatomic, strong, setter=setVariable:, getter=getVariable) NSObject *var;
Upvotes: 4
Reputation: 318944
If the values are not being set from the outside then they shouldn't be read/write properties. Make them read-only and use lazy loading in the "getter" method.
@interface GinkgoDeliveryOrdersTableViewController : UITableViewController
@property (nonatomic, readonly) PFQuery * query;
@property (nonatomic, readonly) NSArray * products;
@end
@implementation GinkgoDeliveryOrdersTableViewController
@synthesize query = _query;
@synthesize products = _products;
- (PFQuery *)query {
if (!_query) {
_query = ...
}
return _query;
}
Do the same for the products
getter.
Note that in your original code there was no need for the @synthesize
lines but in this updated code they are needed because otherwise the ivar wouldn't be auto generated due to the explicit getter method.
Upvotes: 7