Skip to content

Archive

Tag: Cocoa

This is a quick introduction to unit testing with XCode. This article does not provide a conceptual overview to unit testing.

As a first step. I did the following:

  1. Go to the project browser and select [ add > new file ]
  2. Select ‘objective c test case class’
  3. The file that opens immediately seems to contain a couple of tests. That, and a link to an overview document graciously provided by Apple.
  4. So I click, and read everything patiently (well, I’m planning to. I can display a lot of patience at times) (1).

One thing worth mentioning is that, up to stage 4 and notwithstanding footnote (1), this is a perfect introduction to unit testing, and a perfect approach to documentation. The IDE provides the way to get us started with what we want to do. The code hyperlinks the documentation.

Setting up a target for unit testing

Now to the point, what we want is write a test suite and, minimally (assuming we don’t have continuous integration, yet) wire it to the main project, so the test suite runs whenever we build.

  1. We need a target to run the test suite. Go to [ project > New Target > Unit Test Bundle ].
  2. Make a group to hold your test classes (Optional. We might as well dump everything, everywhere).
  3. At this point I deleted my first test class and re-created it. That’s because we need to add the test class to the test target (NOT to the main target, so uncheck that when going through the wizard) and the easy-clicky way is via the wizard, when we create a new test class.
  4. Switch the active target to Test (or whatever your test target is named)  and target the simulator (otherwise tests will skip).
  5. Press build.
  6. Press [Build]. If you haven’t modified the sample test class, this should run OK.
  7. Now modify the test class to fail a test, and press ‘Build’. This should then fail the build. If you check build errors and keep unfolding, you’ll eventually find a reference to your failed test, along with whatever you set the assert to output when the test fails.

OK, this didn’t work for me at first. In the sample test class, reassign USE_APPLICATION_UNIT_TEST to zero. USE_APPLICATION_UNIT_TEST doesn’t seem to be for unit tests; this is for tests that require your application (or some other GUI, not sure… ) to be running while you test.

NOTE: I have somehow gotten into the habit of stripping #import <Foundation/Foundation.h> off my .h files. Well. If you’re doing this, you’ll get errors when trying to compile your project classes to the test target. You need to add the project’s precompiled header (*.pch) to the build configuration for the test target (see below).

Running tests every time you build the main project

Now, this is trivial and elegant at once. To ensure we pass the tests before even thinking about running our app, all we need to do is drag the test target inside the main target.

Next time we build (targeting the simulator) test classes compile and run before actually running our app. If the tests fail, nothing runs until we fix the tests :)

Troubleshooting

There are three practical issues that tend to occur when trying to put legacy code under unit test with XCode. In whatever case this results in stupidly broken builds.

  1. Most of your existing source files are missing from the Test target.
    => expand the main target for your project; expand the test target; now select Compile Sources in your main target. select all files in the Compile Sources group (do it from the top right panel) and drag them into Compile Sources in the test target.
  2. Frameworks in use  are missing from the test target.
    => use the same approach as in (1). This time, duplicate content from Link Binary with Libraries.
  3. The precompiled header (.pch file) isn’t applied to the test target.
    1. Right click on the main target and choose ‘get info’.
    2. Select the build tab.
    3. Under Configuration: (top left) pick All Configurations
    4. Scroll down until you find the ‘Prefix header’ entry in the ‘GCC 2.2 – Language’ section. Copy the pch path/name and duplicate it to your Test target settings.

(1) At this stage, not everything being as perfect as it ought to be, I bothered popping a mail window and sending the link to myself. I wished I had an iPad icon on my desktop and could just drag the safari window to it – or the link. Yea. Kiss the future.

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 :)

Get Cocoa source code compiling and running on your iSomething in no more than 24 hours. Read this post.

I. Get a Mac, get a life

1) Register to the iPhone Developer program. it’s not free (~$100), but you won’t be able to put your app on the app store or even test on an actual device if you don’t.
Do this first, it may take up to 24 hours to complete. If your country doesn’t have an online apple store, consider getting remote help as offline registration may take up to 4 weeks to complete, including annoyances.

2) Get a Mac. If you don’t have a mac, you can’t do iPhone. Your mac should  be running Leopard 10.5 or higher. Before you head for the corner shop, download the iPhone/iTouch SDK. Avoid using a WiFi connection – download is about 1.2GB.
I got a ‘bigger’ Mac Mini for about $800. That works like a breeze. Rumour has it that the apple dev environment is a memory hog.

3) Install the SDK

4) Dump useless icons from the dock.

5) Download the MoveMe sample application

6) Start the apple dev environment, xcode and open the MoveMe project

7) Follow that tutorial (or just run the example)

II – wotf**k

You will use Objective-C and the Cocoa framework for development.
If you come frome Java, JavaScript, ActionScript, PHP, Python (or
like me, all of the above) you may experience some inconvenience.

The syntax of Objective-C will surprise you – different method calls, different
signatures, never mind using .h files.

There’s a couple of comprehensive tutorials I found useful:

If you haven’t done much programming, Objective-C is probably not the best place to start. On the other hand, stretching yourself a little might be rewarding as there are many things you can do with apple’s wysiwyg interface builder and not too much programming – either way, you’ve been warned.

I wrote a little note about how to send/view debug output in the console.

III – get your app running on your iPhone/iTouch

1) Follow this link and start the development provisioning assistant. Follow the steps… All this probably deserves an explanation but we’ll keep that for later

2) In xcode, set your environment (top left drop down) to iPhone Device 3.x (3.0, 3.1, …, or whatever works) and  hit Build & Run, then one of the following should occur:
- a. the app loads on your iPhone
- b. you get a quizzical exception
- c. you get a message suggesting the phone’s OS is too old.
At this stage, the easiest may be to upgrade the device OS. Obviously
it *should* be possible to build and run on an older target OS, but  for now, quickest and fastest. If you plugged your iPhone/iTouch, iTunes would normally offer to upgrade to the latest OS supported by your device.

That’s it. You’re now an iPhone developper :). Next time I’ll look into the Cocoa Touch MVC (Model View Controller) implementation and suggest ways you can design your application.