Is it bad to set up a property in the getter method? - objective-c

If I have a property, say an NSArray, that's going to be initialized only once for each instance of my class, is there anything wrong with this:
(in the interface)
#property(strong, nonatomic)NSArray *bubbleArr;
(in the implementation)
-(NSArray*)bubbleArr
{
if(!bubbleArr)
{
NSMutableArray *tempBubbArr = [[NSMutableArray alloc] init];
// get filepath for first speech bubble image for page
NSString *speechBubbleImgPath = [[NSBundle mainBundle] pathForResource:
[NSString stringWithFormat:#"speech_%i_0", pageIndex]
ofType:#"png"];
for(int i = 1; speechBubbleImgPath; i++)
{
UIImage *speechBubbleImg = [[UIImage alloc] initWithContentsOfFile:speechBubbleImgPath];
UIImageView *speechBubbleImgView = [[UIImageView alloc] initWithImage:speechBubbleImg];
[tempBubbArr addObject:speechBubbleImgView];
speechBubbleImg = nil;
speechBubbleImgView = nil;
speechBubbleImgPath = nil;
speechBubbleImgPath = [[NSBundle mainBundle] pathForResource:
[NSString stringWithFormat:#"speech_%i_%i", pageIndex, i]
ofType:#"png"];
}
bubbleArr = [[NSArray alloc] initWithArray:tempBubbArr];
tempBubbArr = nil;
}
return bubbleArr;
}
I've never used custom accessor methods, but this seems like a clean way to set it up, so I don't have to set up each property in my viewDidLoad or elsewhere, and don't have to worry about it being nil. I don't recall ever actually come across code that does this. Is this the recommended way to do it? Also, I'll always want to use self.bubbleArr to make sure this method is called, right?

This is a totally valid way of setting up your property. Apple does this sort of thing very often in their sample code as well as in their project templates. Look, for example, at the core data stack setup in a newly created core data iOS project. As #WendiKidd noted, you have to access your variable through the accessors all the time to make sure this works nicely (which is probably what you should be doing anyway).
In particular, this is a good way of implementing a property of a class that can really only return one thing (which, from your comment, it sounds like is what you're trying to do). If that's your goal, here are some guidelines to follow:
Declare your property as readonly
Declare it in the public header if it should be publicly accessible, or in a class extension in the .m file if it should be "private"
If it can/should be backed by a variable, synthesize the ivar and overwrite the getter as you've done
If it shouldn't/doesn't have to be backed by a variable, declare the property as #dynamic in the implementation and overwrite the getter
Only access your ivar through the accessor
Declaring the variable as dynamic in the 4th point will signal to anyone that looks at your code that you've likely written a custom accessor for that property.

The technique of waiting until you need the contents of a variable to initialize it is called 'lazy loading', and is a valid technique. I'm not sure about doing it inside the getter, though.
I think the problem is described exactly by the last line of your post--yes, you would always have to make sure you called the getter method when you wanted to reference the object, even inside the class itself. It's easy to make mistakes and not do that properly, and it's an especially bad idea if your code could be passed on to another developer in the future. They are absolutely not going to expect that you've set things up this way, and could end up with problems when they expect to be able to access the variable as normal. It is common and accepted practice to initialize member variables inside viewDidLoad.
So yes--this is technically possible, though not a very sound setup, design-wise. I would recommend strongly against it. But if you simply want to know if it will function, the answer is yes.

Yes, if you don't use self.bubbleArray OR [self bubbleArray] you will not be invoking that method.
Other than that, totally a fine way of managing a property's instantiation.

It seems like a clean solution, it feels a bit like lazy loading. But I am not sure I would do it like this.

Related

Objective C Convenience Method Use

I am tring to understand convenience methods.
IF I have a sqlite database containing store details and am returning these store details in a FMResultSet. I am thinking that to create an array of these store details as Store objects, that the best way would be create an object of type Store in one go in a convenience method and add to array.
The Class I have created is as below with convenience method
#interface StoreDetails : NSObject
#property (nonatomic, strong) NSString *storeName;
etc etc etc
+ (instancetype)storeWithStoreName:(NSString *)storeName
TelephoneNumber:(NSString *)
telephoneNumber: etc .......
My ResultSet loop would be as below?
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store =
[Store storeDetailsWithStoreName:[rs stringForColumn:#"storename"]
telephoneNumber:[rs stringForColumn:#"TelephoneNo"]];
[Stores addObject:store];
}
Is my thinking correct as above is is it better to go as below.
NSMutableArray *Stores = [[NSMutableArray alloc] init];
while ([rs next]) {
Store *store = [Store alloc] init];
store.storeName = [rs stringForColumn:#"storename"];
store.telephoneNumber = [rs stringForColumn:#"TelephoneNo"];
[Stores addObject:store];
}
All I am trying trying to understand is why you would use one over the other in noob speak, thankyou.
I think you have a good approach: initializing your Store object in a method of the Store class.
The storeDetailsWithStoreName:... method you have defined is a good example of what Apple calls a factory method (assuming you aren't doing anything weird in its implementation). It's a quite common pattern; Foundation has all sorts of examples: arrayWithCapacity:, numberWithInt:, etc.
With ARC, the simplest examples of these factory methods are nearly identical to a corresponding alloc/init expression, since the developer no longer has to think about autoreleasing objects. But there are still plenty of uses for factory methods, e.g. special instantiation patterns such as singleton or flyweight, including a small amount of common conversion or formatting code for convenience, implementing class clusters, etc. And there's the simple convenience of not having an extra set of brackets and less indentation.
The instancetype keyword is a good choice. This allows you to send the same message to a subclass of Store, with the expectation that the method will instantiate an object of the subclass using the same init method, like this:
+ (instancetype)storeWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)
...
{
return [[self alloc] initWithStoreName:...];
}
In the code above, as it's a class method, the self in [self alloc] is the Class object (either Store or a subclass of Store) rather than a specific instance of Store. This is what allows creating an instance of the correct class at runtime, depending on whether you call [Store storeWithStoreName:...] or [MoreSpecificStoreSubType storeWithStoreName:...].
The alternative to a factory method, or compliment to it really, is to declare a custom init method in your Store class:
- (id)initWithStoreName:(NSString *)storeName
telephoneNumber:(NSString *)telephoneNumber ...
…and use that directly inside your loop, instead of a factory method. Again, with ARC, not much of a difference between the two unless there's extra work you want to do in the factory method. You can have multiple variants of the init method; the standard practice is for all of them to call the most detailed init method, which is called the designated initializer.
I would recommend taking the time to read the Apple documentation pages on standards for class design (I linked to some of these pages above). Since there are a lot of this is based more on convention rather than language design restrictions, it's important to know all about the patterns and best practices for good design and proper behavior of special methods.

Call a method every time a parameter is set on Objective-C (Cocoa)

I currently have a class with 15 properties (and growing), and I'm finding myself having to call an update method every time one of those properties change.
Currently, I'm overriding every setter with a code like this:
-(void)setParameterName:(NSUInteger)newValue {
if (_param == newValue)
return;
_param = newValue;
[self redraw];
}
The method [self redraw]; being the key here.
Is there a better way to do it? Should I be using keyValue observers (the method observeValue:forKeyPath:ofObject:change:context:)?
Notes:
All properties (so far) are assign (mostly enum, NSUInteger, CGFloat and BOOL);
All those properties are set using bindings (method bind:toObject:withKeyPath:options:). Except when loading from the filesystem (which is not important, as I already call the drawing methods on every object after the loading is done);
The value changes are only for the current object. I do not need to be told when changes occur on other objects;
I have other properties that I don't need to watch the changes on it (because it will have no effect on my output and drawing the output is kinda time-consuming).
Thanks!
Since these properties are updated using bindings, which invoke -setValue:forKey:, you can override that method instead of writing custom setters:
+ (NSArray *) keysAffectingDrawing {
static NSArray *singleton;
if (!singleton)
singleton = [NSArray arrayWithObjects:
#"property1",
#"property2",
#"property3",
nil];
return singleton;
}
- (void) setValue:(id) value forKey:(NSString *) key {
[super setValue:value forKey:key];
if ([[CustomClass keysAffectingDrawing] containsObject:key]) [self redraw];
}
(I was first inclined recommend key-value observing but agree it's not the best solution here. I think the reason is in part that there's only one object, and in part because the design doesn't follow MVC. Usually in MVC an object that draws itself isn't the one with all the properties.)
(Added: Ahh, I see. The model is responsible for rendering the properties to a bitmap, and that's what -redraw does. That's fine MVC. To make it clearer, I recommend changing the name of the method from -redraw to something like -updateImage or -renderImage, since it doesn't actually do any drawing.)
You could use the Key-Value Observing to avoid repeating in all properties setter the method call, however i think that calling the method directly in the setter is not the wrong way to do it, and could even be faster ...

Help me understand why: [self propertyName] works while propertyName doesn't

So I had a class defined with a property - we'll call it propertyName for the sake of this example. I had the property setup with #synthesize in my implementation.
I have a method called objectToNSDictionary which basically dumps that property into a dictionary:
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
[self propertyName], #"propertyName", nil];
I return that dict to the caller I use a JSonWriter to convert it to a string and pass it off to some service...
Suffice it to say that the above works. However, my original implementation didn't use [self propertyName] but instead just used propertyName. When I did that, I always had an error saying unrecognized selector sent to instance when I tried to use the object in the caller.
What's the difference in syntax really saying and why does one work and not the other?
When you use [self propertyName] you are referencing the property you defined for your class, via the synthesized getter method. When you use propertyName directly you are bypassing the property and using the class ivar directly. This will work as long as your ivar really is called propertyName, which is not required and might not be the case. Generally its a bad idea to access your ivar directly because doing so circumvents the memory management scaffolding that the compiler generates for you.
You need to post relevant code from your calling class to be able to tell why you are getting a 'selector not recognized' message.

Objects creation and instantiation in objective-c

Given the piece of code below where blueViewController is an iVar.
Question: Why not instantiate the iVar directly?
BlueViewController *blueController = [[BlueViewController alloc]initWithNibName:#"BlueView" bundle:nil];
self.blueViewController = blueController;
[blueController release];
It depends on where you are in your class. If you are in your init (and dealloc) method it is recommended to refer to the ivar directly to avoid any side effects in setter logic. Therefore in the init I would do
_blueViewController = [[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil];
But anywhere else I would do it how you have done it. Then if there is any custom logic in the getter/setter I know it will be run.
To eleborate on #Vladimar's point the synthesized setter for a retain will do some memory management similar to this:
- (void)setMyObject:(MyObject *)newMyObject
{
// If it's the same object we don't need to do anything
if (_myObject != newMyObject) {
[newMyObject retain];
[_myObject release];
_myObject = newMyObject;
}
}
It is much safer to let the getters/setters worry about all this logic any time you set your ivars.
You can initialise iVar directly, but the code you have also handles memory management for the previous blueViewController value. Accessing iVar directly you'll have to release previous value manually before assigning new one.
You can do it all on one line if you want. The important thing is to balance the +alloc with a -release or -autorelease. So, you can say:
self.blueViewController = [[[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil] autorelease];
That's fine, but some folks prefer to avoid -autorelease, and some folks just prefer simpler steps and/or shorter lines of code. Using an intermediate variable as you've done helps in that respect, and it doesn't cost anything.
It depends on whether the property is retain or not. Most object properties are retained; this is what a retain property looks like:
- (void)setBlueViewController:(BlueViewController *)bvc {
if (bvc != blueViewController) { // blueViewController is local ivar
[blueViewController release];
blueViewController = [bvc retain];
}
}
So what you're doing up there is creating a retain count of +2. When you init, that's a +1; the property then retains it, bumping it up to +2. Your dealloc releases it once, which brings it down to +1...and you've leaked that property. Because you are alloc/init-ing the variable, you don't want to use the setter; instead, assign it directly to the instance variable.
By instantiating it directly, it saves you the trouble of that other release—fewer lines of code means fewer errors. You might, for example, have typed retain by accident and not realized it until your program crashes because you retained a massive class...
Of course, as Caleb says you could autorelease, but that's effectively letting the object lie around in memory until the run loop is finished. It's much easier, and gives you more control, to just not worry about that. There's nothing wrong with assigning the alloc/init to the ivar; in fact, that's the best way to do it.

Objective-C - How to implement an array of pointers in a method declaration

Ok, if you take a look at my two previous posts (Link #2 in particular), I would like to ask an additional question pertaining to the same code. In a method declaration, I am wanting to define one of the parameters as a pointer to an array of pointers, which point to feat_data. I'm sort of at a loss of where to go and what to do except to put (NSMutableArray*)featDataArray in the declaration like below and access each object via another pointer of feat_data type. BTW, sorry to be asking so many questions. I can't find some of the things like this in the book I am using or maybe I'm looking in the wrong place?
-(void)someName:(NSMutableArray*)featDataArray;
feat_data *featDataPtr = [[feat_data alloc] init];
featDataPtr = [featDataArray objectAtIndex:0];
Link #1
Link #2
Your declaration looks fine. "NSMutableArray*" is an appropriate type for your parameter. (Objective-C doesn't have generics so you can't declare anything about what's inside the array.)
One problem I see in your code is that you allocate an object for no reason and then throw away the pointer (thus leaking memory).
I don't know what it is that you are trying to do, so here are some things that you can do with an NSMutableArray:
- (void)someName:(NSMutableArray *)featDataArray {
feat_data *featDataPtr = [[feat_data alloc] init];
[featDataArray addObject:featDataPtr]; // add an object to the end
[featDataPtr release];
feat_data *featDataPtr2 = [[feat_data alloc] init];
[featDataArray replaceObjectAtIndex:0 withObject:featDataPtr2]; // replace an existing entry
[featDataPtr2 release];
feat_data *featDataPtr3 = [featDataArray objectAtIndex:0]; // get the element at a certain index
// do stuff with featDataPtr3
}