This is the second and final post about what I wish I knew when I started iPhone development. Last time, we spent a lot of time on memory management and some basic XCode and Objective-C tips. To wrap up, we’ll be focusing on dot notation, Instruments, and App Store tips.
6) Properties and Dot Notation
The concept of properties and dot notation is pretty familiar to developers. In fact, it is so second nature in many high level languages, that some developers may be surprised there’s a term for it.
Just in case you are one of those developers, dot notation is when you access an object’s attributes like so:
string myString = myObject.attribute;
or
myObject.attribute = 'new value';
As developers, we love that. It’s much simpler than using getters and setters (though, in thruth, that’s what is happening in the background).
Objective-C supports dot notation for accessing attributes. The usage is extremely straight forward when accessing the built-in classes. The confusion comes when you need to create your own properties to be accessed via dot notation (which I highly recommend).
Before I continue, please note that the following advice has worked for me very well. I’ve seen it implemented in lots of samples, but there are other ways to accomplish the same thing.
Creating a property is a three step process:
- In the header file of your class, define a local variable that begins with an underscore (the underscore is just good practice)
- In the header file of your class, define a property – the property name should be the same as the local variable, but without the underscore (again, for good practice)
- In the main file of your class, synthesize the property that was defined in the header file and associate it with the local variable
Let’s step through that with an example of a simple class. I’m going to make a Person class and give it a property called name. I know, your mind has just been blown. Stay with me, it gets better.
First in the header file (let’s call it Person.h), we define our local variable:
@interface Person : NSObject {
NSString *_name;
}
Next, define the property (still in the header file):
@interface Person : NSObject {
NSString *_name;
}
@property (nonatomic, retain) NSString *name;
@end
The @property keyword is used to declare a property. (nonatomic, retain) are further instructions regarding the generated property. I encourage you to look up the meaning of nonatomic (and the other options for this portion) on your own. That said, if you are dealing with properties of complex types, you will use (nonatomic, retain) 95% of the time.
The retain keyword is extremely important and can be the cause of much angst if you don’t understand it. This keyword will cause new assignments to the property to be automatically retained (don’t worry, it also automatically releases it’s prior assigned value). More on that later.
Lastly, in the main file (let’s say Person.m), you need to synthesize the newly declared property and associate it with the local variable:
#import "Person.h"
@implementation Person
@synthesize name = _name;
@end
Now, you may be wondering why I like to have my local variable and my property named differently. That has to do with my two rules for dealing with object attributes:
- When dealing with the attribute from inside of the class, DO NOT use dot notation
- When dealing with the attribute assignments from outside of the class, DO use dot notation, but DO NOT allocate, initialize, and assign a value in the same line
Why? It all goes back to that retain keyword from earlier. See if you can figure out why this is bad:
self.name = [[NSString alloc] initWithString:@"Alex"];
Figured it out? Here’s a clue: What is the retain count of self.name after executing the above line of code? It’s 2. 1 for the alloc and another because we used dot notation on a property that was declared with the retain keyword.
It is this behavior that results in examples from Apple that look like this:
self.name = [[NSString alloc] initWithString:@"Alex"];
[self.name release];
The first time I saw that, it made no sense – that is, until I leaked a bunch of memory because I didn’t understand dot notation in Objective-C.
To keep it clear in my mind, this is how I handle attribute assignments from inside of the class:
_name = [[NSString alloc] initWithString:@"Alex"];
The retain count after that line? 1. By using the local variable, I avoid all manner of confusion (and pestilence).
When outside of the class, I prefer to do this:
NSString *newName = [[NSString alloc] initWithString:@"Alex"];
myPerson.name = newName;
Yes, it’s an extra line of code vs. Apple’s method, but it requires me to be actively aware of the memory consequences of my actions.
7) Instruments
Don’t underestimate the power of Apple’s bundled Instruments. These are invaluable in detecting leaks, managing memory, monitoring activity, and much more. I could devote a post to each instrument, but instead I’ll focus on the two that I have found to be the most useful: Leaks and Object Allocations.
Leaks is pretty straight forward, it monitors your application for memory leaks. It is a good first line of defense against poor memory management – much like a compiler is a good way to detect syntax errors. But, just like a compiler, it can’t catch all of your mistakes.
To start the Leaks Instrument, simply select Run->Start With Performance Tool->Leaks from your project in Xcode. It actually also runs Object Allocations, but I’ll get more into that in a minute.
To use Leaks, select Leaks from the Instruments panel on the left. It will auto-detect leaks every 10 seconds, or you can change the interval or force it to check manually. If there are leaks, you’ll visually see an orange spike on the timeline where it occurred and you’ll also get a full list of the leaked objects and their types.
What type of leaks does this pick up? Any time a variable goes out of scope but it has not been released, Leaks can detect that. However, it will not detect a leak if the variable and the objects retaining it are in scope. This is why I like Object Allocations.
Object Allocations has saved me on a number of occasions where I kept running out of memory but was not showing any leaks. By using Object Allocations, I could quickly identify that a certain class of object was getting allocated and staying in memory without ever getting released every time a certain button was pushed.
The “# Net” column of Object allocations is particularly useful as it tells you how many instances are currently taking up memory. You can filter down the objects being displayed by using the search box in the bottom-right of Instruments.
8 ) App Store: Cater to Offline Users
I have a confession. I’ve had apps rejected… multiple times… for multiple reasons. Sometimes the reasons don’t make much sense in my opinion. In fact, in one instance a friend and I tag-teamed on an app that got rejected because of a policy that was “going to be published with the next OS upgrade”. Thanks, Apple.
One reason that made total sense to me was that I had failed to cater to offline users. In my testing, for some reason beyond my comprehension, I had assumed that all of the users would have internet access. This was a stupid assumption, I know. Your users may not be online for any number of reasons (one being that AT&T has notoriously bad service).
How do you cater to these users? It’s pretty simple: If your app has online content, detect if the user is online (see Apple’s “Reachability” app) and let your users know that a connection is required to access that feature of your application.
9) App Store: Release Dates
If you’re a relatively small shop like me, or your clients don’t have a huge advertising budget, some of the best advertising you get is in the first few days that your application is released.
During that period, your app is front page in the primary category you list in. If you screw up your release date, you stand to lose a lot of sales / downloads.
To do this right, make sure that when you first submit your app that you set your release date way in the future (I’m talking 6 months). Don’t underestimate the time it will take to get your app through the review process – it can be a while sometimes. To maximize the time on that front page, wait for the coveted approval e-mail from Apple and then set your release date to the next day.
10) App Store: Mind Your Trademarks
The App Store is a great distribution channel. It is also extremely easy for intellectual property trolls from huge companies to troll for the slightest infringement. Before you release an app, make sure that the name is not trademarked.
In one instance, I accidentally stepped on a legitimate trademark. After a threatening letter, I quickly changed the name of the app and no harm was done.
In another instance, it wasn’t quite so clean. See, I share a last name with a very prominent media company. I used to use my last name in my business name, but was threatened with law suits by said media company that I needed to change my name. Never mind that surnames cannot be trade marked – I simply couldn’t afford to defend against the huge budget of a media giant. So, I backed down.
My point is that they found me through the App Store. Technically, I was not in the wrong, but I could not afford to defend against their claim. Again, be careful with company and app names.