iPhone: When to make an Objective C variable an instance variable? - iphone

Generally speaking, when should you make a variable in Objective C an instance variable?
For instance, say I got an UIViewController with an UILabel. In what cases would I have the UILabel as an instance variable vs doing something like this:
UILabel *label = [[UILabel alloc] init];
//set text of label
[view.addSubview label];
[label release];

If you need a moderately persistent handle on any resource, you should make it an instance variable, if the resource in question should remain at least moderately persistent.
In the example above, then yes; the label should be an instance variable, probably one assigned using an IBOutlet.
Generally speaking, most things that live in UIKit (as opposed to Foundation) benefit from being instantiated through NIB files and subsequently accessed through outlets.
This isn't solely a performance issue; it also has to do with memory management and fragmentation, as well as simplifying, in most cases, translation and internationalization.

To your specific case, if you are going to need to access that label at a later point in time (say to change the text) keeping an ivar will save you some effort trying to find it again.
General reasons would be for persistence, scope, and convenience.

In your particular example, the object is written as a variable so that it can be sent a release message after adding it to a view (which retains it).
The equivalent code without a variable is:
[view addSubview:[[[UILabel alloc] init] autorelease]];
We don't need to send a release, because we're autoreleasing the object.

Related

should I always use self.classvariable?

When coding my iPhone app. Is it always a good practice when setting or getting values to use self? I seem to forget half of the time and recently have been tracking down a bug I believe is related to this.
Should I ALWAYS use self or are there cases when it's not necessary or would cause problems?
Edit:
Here's an example of what I'm doing in the code
else if([CellIdentifier isEqualToString:#"Linked Item"]) {
linkedItemLabel = [[UILabel alloc] initWithFrame:CGRectMake(120, 5, 160, 34)];
linkedItemLabel.adjustsFontSizeToFitWidth = YES;
linkedItemLabel.textColor = [UIColor blackColor];
linkedItemLabel.font = [UIFont systemFontOfSize:17.0];
linkedItemLabel.text = [storedValuesMutableArray objectAtIndex:7];
linkedItemLabel.backgroundColor = [UIColor clearColor];
linkedItemLabel.textAlignment = UITextAlignmentRight;
[cell addSubview:linkedItemLabel];}
This is part of the code that sets up my tableviewcells for a form that needs to be filled. Should I be using self.linkedItemLabel or is this fine?
You have to understand that using self.property is a method call (getter or setter method), not a simple assignment.
You should use the ivar directly only inside the setter or getter body.
Reasons:
1/ Properties are meant to shield you from the retain-release hell. Let's imagine you have a "assign" property, you are using the ivar directly and then you decide changing it to "retain". What you get is a bug difficult to find.
2/ Setters and getters can do additional functionality (e.g. setter can add/remove observers to an object) or logging. If you are using the ivar directly you miss this special functionality.
3/ Setters and getters can be overriden in a subclass.
In small projects you can probably avoid most problems even if you are using ivars directly but on big projects, programmed by a team, you should use only self.property to reduce bugs and improve code maintainability.
It's also a good idea to give your ivar a different name (like property_ or _property because you'll notice when you are using it without self..
If you are not writing a high performance game or mathematic algorithms, don't worry about worse performance when using self.property.
It depends on the case, if you are just using #synthesize to auto-generate the getters, then it would not cause any problems on the getters. Although common OO practices tell you to use encapsulation, you will notice pretty much all apple sample code accesses the ivar directly.
Another common practice to refer to the ivar without using self is to synthesize like this:
#synthesize myVar=_myVar
and use _myVar when referring to that variable.
It would only cause a problem, if you implemented something in your getter, instead of using #synthesize.
As for the setters, it isn't exactly a problem, but you just have to keep in mind that the properties for that ivar will only be applied if you do self.myIvar as opposed to accessing the iVar directly, so for example a property declared as (retain), will only be retained if you do self.myIvar = newValue as opposed to myIvar = newValue.
The issue arises with properties. if you do not add the self., then you end up assigning to the variable directly, missing out on the property attributes e.g. retain, assign and thus messing up reference counting for the item, and thus causing potential memory leaks.
You should use self, unless you have an explicit reason not to.
You must use it with clever and clear understanding.
If you're using so-called dot-syntax (i.e. self.myVariable) it means you're calling a getter or setter of the property, which is actually a selector sending to an object instance, which is pretty heavy within Objective-C run-time. So, if you need just a value of your var - you can call it once and reuse saved state or call directly to i-var (if permissions allow).
Call for getters/setters when you really need them.

Strange variable allocation in iOS book

I have spotted an example in book: "iOS4 Programming Cookbook" that I can't understand:
Tray *newTray = [[Tray alloc] initWithPrinter:self];
paperTray = [newTray retain];
[newTray release];
I can't understand why we need a newTray variable. Why we couldn't just use this code:
paperTray = [[Tray alloc] initWithPrinter:self];
Tray is just a Model Class. paperTray - property: Tray *paperTray;
You don't need the newTray variable at all. The alternate code you posted would be equivalent, and less verbose.
The author may have included the other variable just to make it clear precisely what [[Tray alloc] initWithPrinter:self] does.
The author was probably copying a very common pattern that actually makes sense when you're dealing with properties:
Tray *newTray = [[Tray alloc] initWithPrinter:self];
self.paperTray = newTray;
[newTray release];
Now this is very different! If paperTray is a property that was declared with (retain) (and most properties are) then the second line will actually call a setter that retains the given object again. The above three lines are still excessive, but are actually a common pattern that you'll see in a lot of code (including some Apple's example code, iirc). The other variable makes it clear that you're balancing the initial alloc with a release, since the property secretly retains it again.
You could write this more concisely like this:
self.paperTray = [[Tray alloc] initWithPrinter:self];
[self.paperTray release];
or even
self.paperTray = [[[Tray alloc] initWithPrinter:self] autorelease];
but these don't really save you much effort, and are probably more, not less, confusing if you don't know how properties work. So I usually use the three-line pattern that introduces an extra variable. It's idiomatic.
Again, though, this only makes sense with retained properties. In the code in your post, there is no reason whatsoever to use an extra variable. Either the author was using the pattern without understanding its purpose, or initially was using properties and then changed it without much thought.

Why do people always use reassignment for instance variables in Objective-C (namely iPhone)?

I always see example code where in the viewDidLoad method, instead of saying, for example
someInstanceVar = [[Classname alloc] init];
they always go
Classname *tempVar = [[Classname alloc] init];
someInstanceVar = tempVar;
[tempVar release];
Why is this? Isn't it the exact same thing, just longer?
The short answer: This pattern shows up all the time in iPhone code because it is considered the best way to create a new object and assign it to a member variable while still respecting all of the memory management rules and invoking the appropriate side effects (if any) while also avoiding the use of autorelease.
Details:
Your second example would create a zombie, since var is left holding a pointer to memory that has been released. A more likely usage case looks like this:
tempVar = [[Classname alloc] init];
self.propertyVar = tempVar;
[tempVar release];
Assuming that propertyVar is a declared as copy or retain property, this code hands off ownership of the new object to the class.
Update 1: The following code is equivalent, but not recommended* on iOS, which is probably why most iPhone programs use the first pattern instead.
self.propertyVar = [[[Classname alloc] init] autorelease];
* autorelease is discouraged on iOS because it can cause problems when overused. The easiest way to be sure you never overuse it is to never use it all, so you will quite often see iOS code that uses alloc/init and release, even when autorelease would be acceptable. This is a matter of coder preference.
Update 2: This pattern looks confusing at first because of the memory management that Cocoa performs automagically behind the scenes. The key to it all is the dot notation used to set the member variable. To help illustrate, consider that the following two lines of code are identical:
self.propertyVar = value;
[self setPropertyVar:value];
When you use the dot notation, Cocoa will invoke the property accessor for the indicated member variable. If that property has been defined as a copy or retain property (and that is the only way for this pattern to work without creating a zombie), then several very important things happen:
Whatever value was previously stored in propertyVar is released
The new value is retained or copied
Any side effects (KVC/KVO notifications, for example) are automatically handled

Re-usable Obj-C classes with custom values: The right way

I'm trying to reuse a group of Obj-C clases between iPhone applications. The values that differ from app to app have been isolated and I'm trying to figure out the best way to apply these custom values to the classes on an app-to-app basis.
Should I hold them in code?
// I might have 10 customizable values for each class, that's a long signature!
CarController *controller = [[CarController alloc] initWithFontName:#"Vroom" engine:#"Diesel" color:#"Red" number:11];
Should I store them in a big settings.plist?
// Wasteful! I sometimes only use 2-3 of 50 settings!
AllMyAppSettings *settings = [[AllMyAppSettings alloc] initFromDisk:#"settings.plist"];
CarController *controller = [[CarController alloc] initWithSettings:settings];
[settings release];
Should I have little, optional n_settings.plists for each class?
// Sometimes I customize
CarControllerSettings *carSettings = [[CarControllerSettings alloc] initFromDisk:#"car_settings.plist"];
CarController *controller = [[CarController alloc] initWithSettings:carSettings];
[carSettings release];
// Sometimes I don't, and CarController falls back to internally stored, reasonable defaults.
CarController *controller = [[CarController alloc] initWithSettings:nil];
Or is there an OO solution that I'm not thinking of at all that would be better?
I would personally consider some kind of "settings" class, in the tradition of Objective-C data sources. Set up a class that's responsible for being a "data source" for each individual app: have it provide either a set of methods for the values you need for that particular app, or a single "getValueForKey"-style method that returns the appropriate value.
Either way, the solution:
Keeps values in code
Removes the overhead of one massive plist for every setting, some of which may not be used
Removes the work of splitting out bunches of tiny plist files
Allows you to have other classes call your data source wherever they need it
Gives you the flexibility of OO (you could, in theory, subclass your data source should the situation or need arise)
Localizes the changes you need to make; just include the data source class as part of the set of classes you're reusing from app to app, and tweak just that class as appropriate (rather than having to change things throughout other classes)
Lets you set reasonable defaults - or even throw exceptions - for data values you don't expect to be needed in a particular application, without the need for explicit fallback code in every calling class (write the default or exception once in the data source class)
I would give a delegate member to each class to ask what the fine details should be. What font should I use? I'll go ask my delegate. It does not have to be the same delegate for each class or instance, but it can be. For values that can have defaults, use respondsToSelector: to allow for optional delegate methods.
You could make the delegate go look in an xml/plist file for the details, in which case you have it all in one place and can even download a new file to change little details.
All your classes can have the same initWithDelegate: method, which makes it easier to instantiate one without knowing what it is.
Prariedogg,
Absolutely externalize the settings into something like a plist. You can even have multiple plists that align to the particular situation (e.g. settingsMac.plist, settingsIPhone.plist).
When your app determines what environment it is running in, it loads the appropriate settings via a delegate or a central singleton.
By externalizing it you will reduce the average maintenance cost of the application. There is less cost to managing and deploying plist updates than recompile/retest/repackage/redeploy.
-- Frank

When do I alloc and init objects in iPhone programming with Objective-C?

Sometimes when I program for the iPhone, I wonder when you have to allocate and initialize objects and when not to. When you are using UI controls, it seems as if you don't have to do so. Is this true and why?
(Assume that they have been declared in the .h of the view controller.)
Example:
label1.text = #"Hello";
vs
label1 = [[UILabel alloc] init];
label1.text = #"Hello";
Is this because I'm using Interface Builder? Would I have to do this if I were to write our my GUI in code?
Your confusion is because of the NIB file - a NIB file is basically a frozen object graph (i.e. a object with children, who has other children, etc). When you load that NIB file, the runtime calls all of the allocs and inits for you, so that they're already created.
When you want to create an object that hasn't been previously specified in the NIB file, that's when you need alloc/init.
You basically need to alloc/init ALL objects except for static strings, as above. Even when you're using convenience methods, such as +[NSString stringWithFormat:...], behind the scenes an alloc and init is still occurring. These convenience methods usually just do the alloc and init, and then toss in an -autorelease as well so that you don't have to worry about cleaning up.
If you're just creating a temporary object, and there's a convenience method that fits, use it. If you want your object to stay around and there's convenience method, usually it's fine to call it and add a -retain, or just use alloc/init.
Obviously, if there's no convenience method, use alloc/init.