Skip to content

Archive

Tag: CocoaTouch

After almost a year, my third update to the ObjC beginner caveats blurb. 8 new caveats added today (marked with [NEW])

Language/SDK

1. NSArray/NSMutableArray cannot hold ints or NSInteger
>> although NSInteger is notationally similar to NSNumber, NSNumber is an object while NSInteger is an alias for int or long (depending on whether you’re running a 32/64 bits architecture). NSArray can only hold objects. If you want to add a number to an NSArray, use NSNumber and initialise your number with something like [NSNumber numberWithInt:26].
(Yes, you can use standard C arrays, there are quite a few posts about this around)

2. NSNumber doesn’t auto-unbox
>> If you try to assign NSNumber to an int (or, better, an NSInteger), you’re assigning a pointer, not the actual number. To get the actual number, use something like: [MyNSNumber integerValue]

3. Strings don’t concatenate with [+] or [.]
>>
If something like “Score: “+score is what you’re used to, try making friends with:
[NSString stringWithFormat:@"Score: %i", score];

4. In, (void)applicationDidFinishLaunching:(UIApplication *)application {…}not all IBOutlets depending on your nib file will initialize until your view is added to the main window
after [window makeKeyAndVisible]; it should be safe to access all IBOutlets attached to your viewController.

5. I updated the frame property of a subview, but the coordinates look incorrect.
>> after updating the UIView.frame property on a subview, invoke setNeedsLayout on the parent view.

6. NSTimer fires at the wrong time / fires too many times
>> When you allocate/init NSTimer with the usual code, you don’t need to invoke fire(). NSTimer is setup as soon as it’s initialized and fire() shouldn’t be called directly as it, *doh!* fires the timer.
>> Whatever you name your callback method, it should take a unique NSTimer argument ( the selector argument would typically look like @selector(myCallback:) with the semi-colon at the end).
What happened to me is that my timer kept firing over and over even though repeat:NO was set. Adding the timer argument to the callback fixed the problem.

7. You cannot declare new variables inside a switch statement

switch (foo) {

case BAR:

char foobar=’*'; // compile error

break;

}

Use this instead:

char foobar;

switch (foo) {

case BAR:

foobar=’*'; // OK

break;

}

Memory Management

8. Use NSZombieEnabled to crash and get a call stack when your program attempts accessing a deallocated object [NEW]

Google it…

9. You need a symbolic breakpoint to hit malloc_error_break and get a call stack [NEW]

Google it (I feel lazy).

10. Unless otherwise stated, objects allocated as a side effect of calling methods other than [alloc] are autoreleased.

This is especially applicable to objects created using factory methods. Take the following example:

[NSMutableArray arrayWithCapacity:5]; // will be released automatically

[[NSMutableArray alloc]initWithCapacity:5]; // we just created a zombie!

At first, it would seem that [NSMutableArray arrayWith...] forms are just shorthands for [[NSMutableArray alloc] initWith…]. Hell, not quite.

[NSMutableArray arrayWith...] and other, similar factory methods, ‘emulate stack allocation’ for reference types. This means that we don’t need to worry about releasing them, as the so-called autorelease pool will take care of them for us.

When we check our code for memory issues, knowing which objects are kept in memory (on the heap) is essential. One way to learn about these is to scan for alloc, retain and release statements. The so called ‘shorthand forms’ allow using objects transiently, without worrying about memory issues, so this convention can help reduce the time spent on memory management.

There are downsides to this for unfortunate beginners:

(1) When we start with objective c, the [alloc[init form appears verbose and cumbersome. So we're likely to create our own shortcuts -- generating 'silent allocations' that make memory management harder.
(2) If we use the 'shorthand' forms, we quickly end up with weird, hard to fix bugs, because we might end up assigning auto-releaseable objects to variables, then these objects get deleted implicitly, and finally we end up accessing... ...garbage(!!!).

11. Beware of  abusing autorelease [NEW]

Autorelease is useful and in some cases you cannot avoid using it:

  • Objects returned by factory methods
    A(n essential) convention dictates that objects created using [alloc] have a reference count of 1. In contrast, callers of factory methods are not responsible for releasing returned objects unless they retain them (see #10)
    Since we can’t use [release] before returning an object we just created, we need to use [autorelease]
  • An object on the call stack may get deallocated if [release] is called.
    Now, it may be argued that only bad design can cause this to happen. Nevertheless one way to solve the problem (it can get nasty) is to use [autorelease]

Now that this is out of the way, beware of practices involving using [autorelease] as a ‘default safe way’. Here’s why:

If an object deallocates unexpectedly following a call to [autorelease] the call stack above [dealloc] doesn’t tell you what caused this object to deallocate.

I don’t see how a coding style involving loosing track of deallocation events can be safe.

12. You can crash the leaks tool in Instruments (seen in Instruments 4.0, 4.1) [NEW]

Recently I managed quirky memory management code that didn’t crash on device or in the simulator, yet crashed instruments. Checking the details, I stumbled on something like ‘invalid leaks data’.

I was about to use up one of my support tickets but reflected that sending my code over and waiting for the ticket to process would take a lot longer than reverting my changes and use the weak muscle to figure it out.

On the downside I got lucky before I managed to narrow it down.

Even if you’re not part of a team, consider using versioning (SVN or whatever new-fangled stuff you’d like).

Kind reminder:

No versioning
=> no diff tool
=> no way to accurately revert changes
=> panic
=> loss of money
=> loss of sleep
=> loss of hair(*)

(*)If you are bald I trust this won’t be an issue.

13. WTF my code crashes when ‘unplugged’ [NEW]

Consider the following case:

  • Your code doesn’t crash when debugging on-device.
  • Your code doesn’t crash when debugging in the simulator.
  • Your code crashes when running in the simulator after pressing the app icon.
  • Your code crashes on-device when running after pressing the app icon.

Then try this:

  • Disable NSZombieEnabled. Quite possibly you’ll see a fairly non-descript crash in the debugger when running the same code.
  • Try to isolate the stack that causes the crash (it’s not meant to be fun but using a dichotomy you might get it done in less than an hour)
  • Re-enable NSZombieEnabled. At this point you may see inconsistent variable assignments in the debug window.
  • Set breakpoints on [dealloc]. Quite possibly you’re deallocating an object that’s already ‘somewhere up’ on the call stack. On sunny days this crashes the device/simulator (hey, it’s actually a GOOD thing). On rainy days it drives the debugger crazy.

Build errors & warnings

14. Warning: Multiple Build Commands for output file …

In XCode, the name of a resource (e.g. a picture to include in the build as resource) is different from the path the resource is retrieved from. Several resources can have the same name, linked with different paths. So for example we can have:

  • foo.jpg (/images/foo.jpg)
  • foo.jpg (/mypics/draft/foo.jpg)

In the final bundle, however these resources are in conflict, they both target /foo.jpg. XCode will issue a warning if resources conflict in this way.

Unsurprisingly, this typically happens when reorganizing project resources.

15. Linking C++ libraries [NEW]

If your project depends on C++/ObjC++ libraries, you may need to add -lstdc++ to other linker flags to your build (see here).

Nibbling UIs (Interface Builder)

16. Action mappings are one-to-many

Yesterday I copied a button from my UI and bound an action to it. Then I was rather puzzled to find that, when I clicked on this button, my game started off with an ominous GL error code. I thought binding an action to a button overrides the previously bound action. It doesn’t. The same user action on the same widget can bind several IBAction targets. In my case this caused the game’s start method to be called twice.

Asset management

17. Use the blue folders [NEW]

If you have hundreds of assets, adding them manually will be a pain. However you can link a whole folder; in XCode’s ‘add files wizard’ select your folder and tick create folder references automatically…

XCode is getting better at detecting changed/added assets between builds (but see #18, below)

18. Sometimes you need to remove your app from the simulator/test device [NEW]

If your code relies on a mechanism allowing to retrieve a resource from one of several locations, you need to delete your app from the simulator / device whenever you remove assets from a blue folder.

Let’s say your sound folder is organized like this:

default_sounds/
---- KO_sound.caf
---- goblin_sounds/
-------- KO_sound.caf

Now suppose you deleted KO_sound.caf under goblin_sounds. Well the goblin specific sound recorded from your little sister’s performance will still load and play because it doesn’t get removed automatically.

Between builds, no files are deleted from package contents. I don’t know whether it’s a bug or not. It’s often annoying.

OS3.0 compatibility: getting the frame callback right.

The minimum compatiblity target for new apps is OS3.0

First, look at the code sample below

animationTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)((1.0 / 16.0) * animationFrameInterval) target:self selector:@selector(drawView:) userInfo:nil repeats:TRUE];

Yes! This code intends to set the frame rate to 16FPS. I started freaking out when running in the OS3.0 emulator and getting a slow, slow, slow frame rate. I started losing faith in NSTimer, not as accurate as CADisplayLink but… …until I spotted the animationFrameInterval multiplier. I’m targetting 20 FPS now, so my frame interval is 3 (60/3), yielding (in the example above) a frightening 5FPS.

Glitching frames

I’ve been feeling a little moody lately because my renderer started ‘glitching frames’. Pausing briefly and periodically. And I’ve been blaming a bit of code I wrote that gets out of the way every really-too-far-to-render object every once in a while (about every second). OK, this iterates a potentially ‘big’ list (how big is big? actually less than 500 elements at most – doh!).

Turns out I’ve been initializing / restarting an AVAudioPlayer at every blooming footstep. If you want footsteps, use a sound loop, and do it the right way…

Status update

This week-end I cleared my dev tasklist. Today I cleared my artwork list and tomorrow I’m getting the sound release ready. Then I should get busy with last minute testing and routine instrumentation while my promotion material is getting ready.

What’s up with the smileys?

Yes! WordPress converts Objective C into strings of smileys. How cute.

Today, I ‘rescued’ my game project  by migrating all my sources to a sample project file. My original problem clearly came from the source project settings. Since this is my first serious project, I possibly messed with my project settings at some point, and as a result a couple of files refused to get into the main bundle.

A great thing about CocoaTouch development is that XCode provides pre-configured projects which (in the closed world of iSomething development) just work out of the box so we don’t need to learn about the many many gritty details. Unfortunately this can lead to panic when a configuration/build level problem occurs.

For this time, I used a solution that won’t get me an award, but saved my digging further into a nasty problem for which no documentation or online help seems to be available – in short, I duplicated a sample project (containing the code I couldn’t integrate with my old project) and moved all my project files (~130) over. Something you might want to try if you’re having odd build/project configuration issues.

Here’s the steps I followed:

  1. Duplicated a sample project.
  2. Put aside all project source files in a separate group (some stuff can’t be put aside because it can’t be moved, e.g smart groups, targets, frameworks…)
  3. Moved all groups (what looks like folders in XCode, but isn’t) from my old projects to the new project. I did that by dragging and dropping from the source project to the target project, checking the ‘copy as needed’ box at the top. I moved my groups into a new group to keep things tidy.
  4. Step (3) will normally fail with conflicting files. The simplest approach in this case  is probably to replace the conflicting files (in my case, MainWindow.xib and main.m)
  5. Deleted (or at least put aside) unused nib files from the sample project.
  6. Added the frameworks missing from the new project.
  7. Run a build to make sure everything builds OK.
  8. Run the app to make sure I’m running my app versus the sample.

At this point, the template project settings pointed at my application (because the real entry point is the main nib file, and that is a file I replaced).

Note that it may not be a good idea to try replicating the target/creating a new target, especially if you haven’t done that before. In my case, I just use the existing target. For now there’s a few names that don’t match my old project, but these names are cosmetic – no logical dependencies – so it’s OK.

A couple of caveats:

  • I ran my first test build before moving conflicting files over -  this worked because the files that conflict tend to be top level in the dependencies hierarchy. But after overriding the conflicting files, XCode  didn’t detect the change and kept reusing old images from the previous build. I deleted the build folder attached to the project and ran a fresh build.
  • Quite a few warnings appeared. Because of dynamic binding, sometimes XCode can’t detect what’s right or not. These warnings have a way to disappear when running the next builds, but then recur after moving files over to a new project. It’s better to avoid getting any warnings at all if possible. In this particular case, I just went through the list to make sure nothing evil leaked into the project while migrating files.

OK, no glory here, but if like me you got into iSomething dev. by chance, just want to be productive and don’t want to learn all the details of the build process and project config, this might help.

The apple dev center feels like a foggy, non linear nebula of documents – not really convenient either to get a comprehensive overview of how stuff works, or to come back to something I viewed before.
Here’s a few pointers to the most useful resources I found - Hope this helps you too.
If you’re completely new to the game, you’ll need to setup for iPhone development. Read my article for getting Started in 24 hours or less.

Application Programming - covers generalities, UI and event handling, graphics and IO.

  • View Controller Programming Guide – explains how to use view controllers in the CocoaTouch MVC paradigm. Explains how to manage tabbed panes and navigation bars to create multi-page displays of information.
  • Core data frameworks and device services -  somehow,
    Getting started with data Management provides links to various data frameworks, as well as how to handle touch events, geo-location, the accelerometer and device orientation.
  • Coding How-Tos - Covers much useful stuff with a hands on approach, unfortunately, sample code isn’t always provided.

Networking - Getting Started With Networking & Internet links various
(low level/compatible/object etc…) APIs for networking.

  • Networking for Peer to Peer Gaming - The GameKit programming guide introduces P2P networking over bluetooth and voice chat.

Application Management

The following pointers relate to the process involved in getting your application to be distributed on the app store.

Non-Apple resources

There is definitely a few blogs and other websites out there definitely worth reading:

Disclaimer

NONE of the above links is pointing at content created by the author of this blog. The content pointed at belongs to it’s respective owners. This article is not endorsed by Apple or iCodeBlog or whomever else.

If you’re trying to write your first iPhone/iTouch applications or are struggling to put together a small to medium size application, this article may help.

This article assumes you have the ‘kind of understand’ feeling about MVC that most programmers get after digging up a little material on the topic.

A Basic Model View Controller (MVC) setup

In xcode, select new project > view based application. The following classes are created for a ‘Z’ project:

ZAppDelegate – Application Facade
ZViewController – Root controller

The only classes missing are a view class and a model class.

Basic view setup:

  • Create a ZView class if you need to customise the view provided by ZViewController.xib programmatically. Assign ZView as class of the root controller’s view from the property inspector in interface builder.
  • If you only want to gain access to UI elements added to the view, do the following:
  • 1 –  open ZViewController.xib and add your UI elements. In this example, I assume a label (UILabel class) was added.
    2 – add an IBOutlet field to ZViewController.h, like this :
    IBOutlet UILabel* myLabel;
    3 – In ZViewController.xib, notice that myLabel now appears in the file’s owner property inspector (click the blue arrow pointing right in prop inspector to view outlets). It has a little keyhole on the right.
    4 – From myLabel‘s keyhole, click-drag a connector to the actual label.

    Step 1 creates the actual UI element. Step 2 allows programmatic access to the created UI element. Finally, Steps 3 and 4 ensure that the field we have created maps to the actual UI element.

Basic Model Setup
Now suppose we created a ZModel class to hold our application data model. We probably want to gain access to the model from the controller. With a model driven view (view is mainly required to reflect model state), it is often convenient to keep a reference to the model from our view as well. This brings two questions:

1 – Where do we create the model? In other words, when should it be initialized?
2 – How do we provide the controller and view a reference to the model

These questions can be answered in various ways. For simple applications, here’s a recipe that works.

  • Instantiate your model class in ZAppDelegate::applicationDidFinishLaunching
  • Still in the same function, assign the model to the controller and view.

ZAppDelegate naturally owns a reference to the controller (viewController) and view (viewController.view). This makes it a convenient placeholder for our data model. Besides, even if we change the controller and/or view while the application is running, we can still access the model root. Finally, applicationDidFinishLaunching clearly holds the code used to add the view to the main window, so we are sure that the view binds the model before getting rendered the first time.

Processing user interaction

If your view is processing touches (touchesBegan etc…) it may be convenient to assign a backward reference from the view to the controller. Again, this setup can be effected from applicationDidFinishLaunching. We can then query the controller to perform high level actions when touches occur.
You can work around potential (compile-time) cyclical dependencies between the view and controller by only referring the controller using an
@class ZViewController
annotation before your interface declaration/class def. Although this may trigger a warning, you don’t need to import ZViewController to invoke methods on it as Objective C resolves method calls at runtime.

That’s it for now…

If your application is becoming complex, you may need to look into more developed MVC solutions – e.g. get inspiration from the PureMVC framework or maybe try my F* Meta-Pattern.

So much for commonsense. What’s the difference between:

NSArray *foo=[NSArray arrayWithObjects:a,b,c];

and

NSArray *bar=[NSArray alloc] initWithObjects:a,b,c];

Should be pretty much the same thing, right?

As it stands, I populated NSArray/NSMutableArray with UIImage pointers. Trying to use any UIImage* from the resulting arrays consistently crashed the iPhone simulator using …arrayWithObjects:… .

From now on I will always use …alloc]initWithObjects:…
instead.

Don’t take my word for it, try this at home :)