Archive

Archive for the ‘iPhone Development’ Category

Writing private methods in Objective-C

January 8th, 2010

So there isn’t a real way to write private methods in Objective-C.

What I tried to for a while is to just write the methods in the .m file and simply omit the declarations in the .h file. This would be quite annoying when you call the private methods before they are defined in the .m file because Xcode would give warnings.

One convention we’re using to deal with this is to define a (Private) category at the top of .m file containing all the declarations of the private methods. By doing this, you’re letting the compiler know that  about the “private” functions that these functions will exist, so the warnings go away. It’s also a nice way to communicate to the readers of your code that the methods are private. The (Private) category is defined inside the .m file, so it really remains, well, private.

Here is a real example from our Say a Secret project:

#import “BadAssButtonController.h”
#import “ButtonUtil.h”
#import “Debug.h”

// Private methods

@interface BadAssButtonController(Private)

-(void) doneAnimating_;

@end

@implementation BadAssButtonController

@synthesize overlayImage;
@synthesize button;
… blah blah

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development

2010

January 8th, 2010

holy crap I just realized that 2 in binary is 010. 2 + 010 = 2010. Do you know what this means? It’s the end of the world of course.

Well, whatever surfing that I missed out on during the summer of 2009 because I was too busy cutting PNGs for Say a Secret ™, I’m doing it these days. I’m actually going out to Pacifica tomorrow. There are swells coming in, and the conditions are supposed to be good. I’m feeling even better because I got home about 30 minutes ago and fixed a bug (that I created a few weeks ago which went unnoticed) without too much hassle. All thanks to a small bit of reading I did over the summer.

The book is Cocoa Programming for Mac OS X. This book is badass. It filled all the gap in my knowledge about Xcode, Cocoa, Objective C in one schbang. Thanks Aaron, you’re awesome. Chapter 1 even ends with a little motivational section on “How to Learn.”

Besides the general badassery of the book, I want to point out one of the strongest aspects, in my opinion of course, of this book - it is very hands-on. It doesn’t try to sugar-coat with dense jargon or make you feel itty-bitty by using theoretical mumbo jumbo. It even tells you *gasp* how to debug. And it was what I learned from this section of the book on how to debug that saved the day.

We’ve all seen it - the cryptic stack traces you see in Xcode when things foobar:

2008-08-01 21:10:20.138 Tomatoes[151:20b] *** Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘*** -[NSCFString replaceCharactersInRange:withString:]: Range or index out of bounds’
2008-08-01 21:10:20.213 Foobar[151:20b] Stack: (
808163835,
806099672,
807978623,
807978527,
812533155,
812164939,
812716685,
22067,
35325,
812317455,
812317325,
824032771,
824024301,
824022997,
807779567,
807777675,
829004012,
816177936,
816214500,
8381,
8244
)
terminate called after throwing an instance of ‘NSException’
kill
quit

I’ve seen some tips on how to decode this stack trace using ‘atos’ or whatnot. Guess what, I’m too lazy for that. I’d rather sprinkle NSLog statements than cut & paste some numbers around.

News flash! There is an easier way folks!

Step 1: From the menu go to Run -> Manage Breakpoints -> Add Symbolic Breakpoint, and add “objc_exception_throw”. Now you’re all set - your Xcode is now badassified to automatically break whenever you write crappy code that throws an uncaught exception.

Step 2:  Write crappy code and make your code crash. C’mon, you know how to do this.

Step 3: Run your code - when it craps out, you’ll see the ‘(gdb)’ prompt and your program has auto-suspended.

Step 4: Find that little spray can icon back in your Xcode IDE. It’s somewhere right above the editor.

Voila, now your see the stacktrace right in your IDE. No commandline incantation or nuttin. Now let’s go back to life & surfing.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Uncategorized, iPhone Development

Extremely Useful Debugging

August 26th, 2009

More likely than not, your application will have crashed at some point in its development cycle. And you will have seen a cryptic message like this on the console.

2009-08-19 13:45:19.059 TestApp[3905:20b] Stack: (
2478641131,
2426342971,
2478670314,
2478663660,
2478663858,
92386,
816691521,
816216343,
816148479,
816144864,
827743722,
827753484,
2478142405,
2478144168,
827745792,
827745989,
816114848,
816160924,
9656,
9510
)

The problem is that you have no idea where in the code the crash is happening. Java’s stack trace is very descriptive, with function names and line numbers. This is also possible in XCode, but you have to take an extra step.

Run your iPhone application and then wait for it to crash, displaying the stack trace as above. The program will have paused at this point. If you go down to the console, you’ll see a prompt that says (gdb), where you can type in gdb commands.

Look at the stack trace above, and try to find a small number somewhere in the middle of the stack. This is likely where your program crashed. In the example above, this number is 92386. Once you have identified this number, you can now identify more helpful information about the crash.

Issuing the command: info symbol 92386

Will give you something like this:
-[MainViewController touchesEnded:withEvent:] + 164 in section LC_SEGMENT.__TEXT.__text of /Users/Min/Library/Application Support/iPhone Simulator/User/Applications/877EB45A-AB6B-4CD5-AA43-C7B0F2C98F7B/TestApp.app/TestApp

Issuing the command: info line *92386
Will you give something like this:

Line 416 of “/Users/Min/Documents/Projects/TestApp/Classes/MainViewController.m” starts at address 0×168b5 <-[MainViewController touchesEnded:withEvent:]+119> and ends at 0×16985 <-[MainViewController touchesEnded:withEvent:]+327>

So there you have it. You now know that the crash took place in the [MainViewController touchedEnd:withEvent:] message on line 416.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development , , , , ,

Threads and Waiting

August 24th, 2009

Proper use of threads will do wonders for your program’s responsiveness. It will also do wonders in making your code harder to follow. What if you have a thread churning along in the background and you’d like to know when that thread has produced a value before continuing on with your work? Maybe you have a thread called ComputeWinningStockThread that takes all the data from the stock market, applies some magic formula and spits out stocks that are going to make you millions in random time intervals.

1. Start ComputeWinningStockThread in background.
2. Until ComputeWinningStockThread has picked a stock, continue checking to see if it has.

This is the poor man’s version. It is also called the busy loop or polling. And it uses up valuable resources that your iPhone could be using for other things.

The proper way to handle this is with the NSConditionLock. You can use NSConditionLock to have one thread wait for notification from another thread before continuing. Or, in other words, it blocks until a condition is met (hence, the name conditional lock).

In Objective-C, this is the gist of what you would have to do.

1
2
3
4
5
6
7
- (void) ComputeWinningStockThread {
    while (YES) {
        [myLock lock];
        winningStock = [self someSecretAlgorithm];        
        [myLock unlockWithCondition:0];
    }
}

Then maybe in another message, you are calling this thread to earn your millions.

1
2
3
4
5
6
NSConditionLock *myLock = [[NSConditionLock alloc] initWithCondition:0];
[NSThread detachNewThreadSelector:@selector(ComputeWinningStockThread) toTarget:self withObject:nil];
 
// This will block until it is unlocked in the thread
[myLock lockWhenCondition:1];
NSLog(@"I have a winning stock! %@", winningStock);

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development , , , , , , ,

Handling didReceiveMemoryWarning

August 20th, 2009

Predicting user behavior on the iPhone is difficult. One can never know how many pages of Safari someone might have in the background hogging up valuable resources. Every now and then, I get reports of our application crashing for no apparent reason. More often than not, it’s caused by the phone running low on memory. It’s amazing how little memory we have to work with on the iPhone. With Safari taking up 8 pages in the background, our application was crashing at mere 8 MB of memory usage.

Load Late and Lazily

Sometimes you have to sacrifice the snappy UI for a low memory footprint. It’s better than your application crashing. This means never preloading resources but waiting until the moment you need it. If your XIB (NIB) file has a lot of views, try separating them into multiple NIB files so that you can load it individually when you need it. When a view is not visible, the system will free it from memory.

- (void) didReceiveMemoryWarning

The didReceiveMemoryWarning message will be called when the iPhone is running load on memory. It is highly recommended that you override this message in all your view controllers and print out a simple debug message in it. Also, do not forget to call [super didReceiveMemoryWarning].

- (void) setView:(UIView*) view

If you receive the didReceiveMemoryWarning message, the setView message will be called with a nil parameter. It will be called to release the view if the view is not the active view. This is where you will want to release as much resources as you can, such as all your IBOutlet variables. Also, do not forget to call [super setView:view] or your application will crash.

Initialization

Once your view is freed, the NIB will be read back into memory when it is needed. This means the viewDidLoad message will be called again. So take care not to place initialization code that should only be initialized once per application in that message.

CLANG Analyzer

If you haven’t tried this tool already, then you are truly missing out. Check out this extremely helpful post by Jeff Lamarche, the author of Beginning iPhone Development. CLANG will analyze your code and give you a detailed report of problems your code may have, including memory leaks.

Also, If you’ve missed my previous post about the dangers of UIImage, you can check it out here.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development , , , ,

Memory Management Pitfalls

May 21st, 2009

I thought that, for the most part, I was done with memory management after moving on from C/C++ to Java. But we all know that was not to be, so I’ve created this quick reference sheet for my own reference that some of you may find useful.

Pitfall 1: The order matters
Assume we have a setter method in some class.

1
2
3
4
5
6
7
8
9
-(void) setText:(NSString *)newValue
{
   if (newValue != text)
   {
      [newValue retain];
      [text release];
      text = newValue;
   }
}

The NSString that is passed into setText may be another NSString. So the value that is passed in must be retained, because we can’t have the memory freed until we are done with the class. We release text because it is being repaced with newValue.

Note that it is wrong the write the code above as

1
2
3
4
5
6
-(void) setText:(NSString *)newValue
{
      [text release];
      [newValue retain];
      text = newValue;
}

This is a due to a somewhat subtle case when text and newValue points to the same instance of NSString. By releasing text, newValue will also be released.

Pitfall 2: Using the dot (’.') notation incorrectly

self.text = newText

is actually a shorthand form of

[self setText: newText]

Thus, it will retain newText, increasing the reference count. Do not confuse it with how it works in a language like Java.

this.text = newText

is different from

self.text = newText

Because the first is a direct assignment and the second is actually a message call.

Pitfall 3: Not following the fundamental rules of reference counting
The fundamental rules are:
1. If you allocate, create or copy it, you need to release it.
2. If you retain it, you need to release it.

Consider the following snippet of code

SomeObject *newObject = [[SomeObject alloc] init];
self.object = newObject;
[newObject release];

newObject needs to be released to balance the retains. The first retain is in the alloc call, and the second retain is in the setObject (aka self.object = newObject) message.

Also, if you write something like this

self.object = [[SomeObject alloc] init];

the retain count will be at 2 because it is retained once for the alloc and one more time for the setObject message.

If you’d like to read more about memory management, here is another post that I wrote about the topic (I also talk about NSAutoReleasePool a bit here).

This wasn’t a comprehensive overview of memory management, but I hope it was somewhat helpful.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development , , , , ,

iHappyBirthday 1.1

February 8th, 2009

Fix and a Solution

Thank you to everyone who has purchased iHappyBirthday. Reaction to iHappyBirthday has been quite positive. However, we’ve been receiving reports of random crashes. We actually know why this happens. In a previous, unreleased version of iHappyBirthday, we displayed an alert message to the user telling him or her that the system is running low on memory; and that continuing without freeing up memory may crash the application.

But we removed this message because according to our tests, the phone did not reach such a low level of memory that it would cause it to crash. However, iHappyBirthday 1.1 uses a little bit more memory than 1.0, and that seems to have pushed it over some threshold which is making it more prone to crashing. We are happy to say that we have solved this problem by drastically reducing the memory usage. We have submitted version 1.1.1 and it should be available soon for download. But in the mean time, please follow the workaround from our support page.

Technical Mumbo Jumbo: iPhone Memory Management System

I’m writing this for the benefit of other developers who may be facing similar memory problems. Or if you are not a developer and just happen to be a glutton for pain, then please read on. Our application was not using that much memory, but when other applications (like Safari) were taking up over 20 MB of RAM, it would cause our application to crash due to the phone running low on memory. The following were my observations while chasing down this problem.

When the iPhone runs low on memory, it will start freeing memory from background applications like Safari. But why then was our application still crashing? This was because the rate at which our application was using up the memory was greater than the rate at which the operating system was freeing up the memory. Ultimately, it comes down to this simple fact:

“Always minimize memory usage.”

It’s not very enlightening, but that’s the fact of the matter. Looking at the Activity Monitor in Instruments, I noticed that the memory used by Safari continued to decrease bit by bit over time as iHappyBirthday was running. And then eventually, Safari was entirely removed and all resources freed. However, if iHappyBirthday was too aggressive in its memory usage, even though the OS was freeing up memory, it could not outpace the rate at which iHappyBirthday was requesting memory. The result? Crash.

UIImage!

For version 1.1.1, the memory use was halved. It was achieved by not using the UIImage’s imageNamed message and by intelligently loading resources. It turns out that if you use imageNamed, the resources are cached into the memory and the iPhone does not do a very good job of releasing the cached memory. For version 1.1.1, imageWithContentsOfFile was used in conjunction with imageNamed. And for the most part, the caching was handled by the application rather than the iPhone SDK.

It was interesting to see how the memory management system behaves on the iPhone. And even more enlightening to learn about the pitfalls of using UIImage’s imageNamed routine. In fact, the documentation for this routine states,

“This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.”

But of course, I never looked at the documentation before using this. Had I looked at it, I could probably have avoided all this mess.

So always remember to RTFM!

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, News and Updates, iPhone Development , , , , , , ,

Let’s be Introspective

January 8th, 2009

As long as we are being introspective about the previous year, let us talk a bit about Objective-C’s introspection. Objective-C is a highly dynamic language (dynamic typing, dynamic binding, and dynamic loading).  It does a lot of things at runtime that other languages do at compile time.  This adds great flexibility. Of course, the trade off is that you lose the security blanket of the compiler helping you out as it looks for errors at compile time.

A practical way I’ve used introspection in an iPhone application is to dynamically assign a control I’ve placed on a view in Interface Designer to an Objective-C object in code.  Take for instance that I have a bunch of UIImageView controls on many views, and I didn’t want to go into each view individually and manually associate it with each of the IBOutlet objects. This can get tedious very quickly.

What you can do instead is use introspection. You can send a view a subviews message and get back an array of all its child views. And each of those child views will have subviews as well, etc. You can use introspection and send the isKindOfClass message to each of the controls on the views to check to see if it is an UIImageView control. Then you can assign these controls to the objects that you’ve defined. Of course, you could have used the custom tag number as well, but then you would have to remember to label all your controls with an unique tag.  It can potentially become a maintenance hassle.

Here is a quick sample code:

1
2
3
4
5
6
7
8
9
int counter = 0;
NSArray *subViews = [self.view subviews];
for (NSObject *item in subViews)
{
    if ([item isKindOfClass:[UIImageView class]])
    {
        myObjects[counter++] = (UIImageView *) item;
    }
}

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, Objective-C, iPhone Development ,

Playing and Recording Sound at the Same Time

December 31st, 2008

My application required that the audio be playing and recording at the same time.  In the early phases of development, I ran into a problem where the application would not record while a sound was playing.  If you are running into this problem, I recommend looking up the Audio Session Programming Guide in Apple’s SDK documentation.

If you don’t feel like reading through all that documentation, the simple answer is setting the audio session category to the proper value.  I had it set to kAudioSessionCategory_RecordAudio.  This records audio only and prevents all playblack.   To play back audio and record at the same time, it must be set to kAudioSessionCategory_PlayAndRecord.

Note:  This was using Audio Queue to record and play back sound.

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, iPhone Development , , ,

A Few Tidbits

December 29th, 2008

Being that the iPhone is a multimedia device with multiple input sources that actually works well as a multimedia device with multiple input sources, I ran into quite a challenge when I tried to implement a few features that took advantage of this fact. The biggest challenge of them all was the implementation of the Fast Fourier Transform (FFT) algorithm for a discrete signal from the built in microphone.

I dozed off during the lecture when the professor was talking about the Fourier analysis and FFT.  The algorithm itself wasn’t too hard to implement because there is an abundance of information on the internet.  But what did prove to be a barrier was the technical details (and also limitations) of the iPhone.  For example, I had to somehow intercept the audio packets from the microphone and send the data off to my FFT function for analysis.

The program ran fine on the iPhone simulator, but I ran into performance problems on the device itself.  Another problem I ran into was figuring out what to send to my FFT function.  I got the best results by converting the bytes passed into the AudioQueue’s callback function into a 16 bit, big-endian, signed short integers.  By best results, I mean that the program can distinguish between different frequencies reasonably well.  I’m not sure whether the frequencies are correct, but I achieved what I was aiming to achieve, so I’m happy with the results.

I’m still trying to figure out the best way to recognize different sounds.  But this is a big and complex field of study that I don’t expect to solve in just a few nights of study, so I will have to come up with a reasonable heuristics to achieve my goal.  I’m at a point where things are working adequately, but I’d still like to see if I an improve it a little more.

Finally, this little piece of fact drove me nuts.  I was trying to detect a touch on an UIImageView.  It turns out that in order for it to receive events, you have to explicitly turn on “User Interaction Enabled” and then subclass UIImageView and override the callback function.  Had I read the documentation a bit more instead of jumping into it…  Oh well.

The application is still on schedule for the end of January release date.

Hope everyone had a great Christmas!

If you enjoyed this post, make sure you subscribe to my RSS feed!

Development, iPhone Development , , , ,