Retail Evolved

Skip to Main Content »

Search Site
Home of the Original Facebook Like Button for Magento

You're currently on:

10 Things I Wish I Knew Before Making an iPhone App, Part 2

Sunday, January 10, 2010 1:13:47 PM MST

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:

  1. In the header file of your class, define a local variable that begins with an underscore (the underscore is just good practice)
  2. 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)
  3. 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:

  1. When dealing with the attribute from inside of the class, DO NOT use dot notation
  2. 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.

 

0 Comments | Posted in Developers By Alex Nielsen

10 Things I Wish I Knew Before Making an iPhone App, Part 1

Sunday, December 20, 2009 11:30:43 PM MST

Creating your first iPhone app can be a challenging experience. For me, it made developing fun again, but only after coming to terms with some concepts that were strange to the Microsoft-wired, C# spewing machine that I call my brain.

1) Memory Management 101

You’ll see that a few of these points deal with memory management. It’s a potentially confusing concept to those of us who have never had to deal with it before. This single concept added probably 20 hours of mind-numbingly tedious debugging to my first app.

Most developers don’t have to worry about managing memory. C#, Java, PHP, Rails, and many more all manage memory for you. What does this even mean? It means that magical memory gnomes automatically “garbage collect” objects that aren’t needed any more. The iPhone SDK doesn’t offer this luxury – you get to play the role of garbage collector.

Let me tell you what will happen if you ignore this concept. Your app will be chugging along nicely until you start watching that embedded YouTube video of your grandma juggling chainsaws when suddenly…crash!

“No biggy”, you say, “I’ll just re-create it and pay close attention to the debugger. It will tell me what I need to do!” So, you start up your debugger, access the video, but nothing happens – it works as expected. “Must be a fluke”, you think to yourself. You continue testing, when …. crash! Out of the blue, the app crashes while testing your tilt-to-scroll functionality. Again, you attempt to re-create, but it’s a no go. Your debugger reads “EXC_BAD_ACCESS” – wow, thanks for the help.

This is a classic case of memory management gone bad. The unfortunate thing with that scenario is that it often won’t start happening until you start testing on devices (the iPhone Simulator is pretty tolerant of unreleased memory – lots more RAM to eat). And when it starts happening, it feels like the gnomes that you used to have working for you are now working against you. Plus, the debugger’s not much help – at least, it won’t tell you where the leaks are happening. You should know, however, that EXC_BAD_ACCESS indicates that you tried to access some memory that has already been released. This either happens because a) You released it and then attempted to access it again, or b) In an attempt to reclaim its quickly depleting memory, the iPhone OS started releasing your views (that’s the default behavior of a memory warning received by a controller).

I could write pages and pages regarding the finer points of memory management, but Apple already has here. You should (must, really) read the entirety of that document. It may sound a bit technical at first, but keep it handy. It will save you hours.

I’ll run down some of the basics as a bit of a primer:

  • Every object has a property called “retainCount” – this is the number of references that have been made in code to the address of your object. This is accessed via [myObject retainCount].
  • As long as this number is greater than 0, that memory stays reserved.
  • A retain count is increased when a “retain” message is sent or when an object is initially allocated.
  • The retain count is decreased by sending a “release” message to your object – [myObject release].
  • When the retain count hits 0, the “dealloc” method of the object gets called and the memory is released (assuming that the “dealloc” method does its job right).
  • A “leak” occurs when an object goes out of scope without being released. You now have no way of releasing that memory…. These are bad and are likely the cause of most major power outages (not really).

Here are some basic rules:

  • Every alloc needs a corresponding release. Make this second nature. Personally, I like to write in the release message at the same time as the alloc message so that I don’t forget. It’s kind of like opening and closing parentheses…
  • In your own class definitions, your dealloc method should release all of the objects it has references to. This includes properties and local variables.
  • When you add an object to an array or dictionary, release it before the original reference goes out of scope. Adding an object to an array or dictionary increases the retain count by 1. This makes sense – the array is taking ownership of the object and retains it so that it doesn’t lose the reference. Later on, when the array is released, all of its objects will be released with it.

So, be a responsible memory manager. It’s not that hard once you get the hang of it. At first, you just need to keep a close eye on your retain counts and use Instruments to help you identify leaks (more on that in a later post).

2) NSAutoReleasePool – Just When Memory Management Was Starting to Make Sense

The points we talked about in Memory Management 101 doesn’t apply 100% of the time. It only applies to objects that are explicitly retained or allocated. So, what happens to everything else? For example:

[NSString stringWithString:@"Hello World"]

There’s no alloc or retain message anywhere in sight, so we don’t have to release it. Yes! You’re off the hook right? Wrong (well, sort of).

See, when an object is created using a class method (as in the above example), it is assumed that the method adds the created object to the most recently created NSAutoReleasePool (on the current thread). “Wait a minute,” you may be thinking, “I didn’t create one of those”. You don’t have to. The application, by default, creates one NSAutoReleasePool on the main thread. When the application exits, it sends a release message to the NSAutoReleasePool, which in turn sends a release message to all of the objects in the pool. Pretty nifty, right?

Most of the time, it’s okay to let small objects such as strings get handled this way. Personally, I still prefer to explicitly allocate and release my strings, just to keep myself in the habit. When should you use NSAutoReleasePool explicitly?

  1. Any time you are performing an action on thread other than the main thread. Threads that get spun off (say, a selector that gets triggered by NSTimer), do not have access to the NSAutoReleasePool on the main thread. Objects that are sent the autorelease message are essentially leaked – there’s no pool to add them to. That is, unless you explicitly create one. Which you should. Just make sure you release it before the method is finished.
  2. Because you prefer to release your objects this way – it’s your style. There’s no problem with creating an NSAutoReleasePool at the beginning of a method and then releasing it before the method ends. In between you can have all manner of autoreleased objects, either because you told them to autorelease or because you used a convenient class method. Just make sure you don’t explicitly release an autoreleased object – you’ll pay later when you attempt to release NSAutoReleasePool.

3) [UIImage imageNamed:@"memoryHog.png"]

Chances are that you’ll need to work with images at some point in the course of your iPhone development. If so, you’ll likely look for the easiest way to grab an image from your application resources. [UIImage imageNamed:] is that method. It’s short, sweet, and you don’t have to figure out the path to your image. Programming bliss…. until you use this method to access a dozen high-res, full-screen images and your app starts crashing (I speak from painful experience).

This method is extremely convenient. And you should use it – sometimes. What isn’t immediately clear about this method is that it loads the image and then caches it in memory in case you need it again. The catch? You don’t have access to the cache where it’s stored – meaning you can’t purge it from memory. It stays there until the application is released.

What should you do instead? It depends, but this is usually a safe bet and gives you finer-tuned control over the release of the image:

UIImage *myImage = [[UIImage alloc] initWithContentsOfFile: @"path/to/my/file"];

The above isn’t a perfect example as you would want to get the path to your resource directory first, but I’ll leave that for you to discover for now. You could alter that method by tacking on an autorelease if you want to use an NSAutoReleasePool.

4) Alt+Double-Click = Enlightenment

Most of the time, SDK documentation is a twisted maze of technical writing. Apple has done a great job of making their documentation easy to access and surprisingly readable. To quickly access the documentation, simply use Alt+Double-Click on a method or class type from XCode.

The documentation will save you many hours of research. Refer to it. Often. If I were smart I would have used it to look up the implications of [UIImage imageNamed] before I learned the hard way.

5) NSLog, a Trusted Friend

In debugging, you will undoubtedly need to output something to the debugger at some point. You can use NSLog to do this. It’s particularly helpful for tracking retain counts and the like. Here’s a simple example:

NSLog(@"%d", [myObject retainCount]);

The first argument is a string format (which you should learn to love), and the following arguments are used to populate the formatted string.

Next Time…

That wraps up part one. Next time, we’ll take a look at instruments and some AppStore tips that will make your distribution easier.

0 Comments | Posted in Developers By Alex Nielsen
 

My Cart

You have no items in your shopping cart.

Newsletter

Newsletter