Monday 8 December 2008

Exploring MapKit #1

For a recent project I needed the MapView from MapKit, the private Mapping API used by the iPhones on-board map application. This is not sanctioned by Apple in any way, and we are not deploying our app using MapKit to the AppStore - it is for research purposes only.

Gaining access to this API is fairly easy, but does require some steps to accomplish.

  • First, get a copy of the Perl script listed here: [arstechnica.com]. Make sure you update the file paths to the right version of the SDK, i.e. 2.1 to 2.2. By default, the Perl script rips the header files of the private api to: ~/HEADERS
  • In XCODE, add the ~/HEADERS directory to the include path.
  • Import the GMM and MapKit frameworks from the iPhone SDK to your project. As these frameworks are not available for the emulator, you will only be able to run your code using these frameworks directly on the device.
  • To include a MapView, you need to import the following:
    #import < MapKit/MKMapView.h >
  • You may have to remove any imports done in MapView.h, and rename the "anonymousstructXX" declared in the header to some sane datatype, such CGPoint. (Use the name of the function as a context to determine the right data type).
  • Add a MapView to your UIView and assign the UIView as delegate with the following code:
    map = [[MKMapView alloc] initWithFrame: frame];
    [map setDelegate: self];
You can point the MapView to coordinates of your choice with the following selector:

[map goToCenterLongLat:<#(struct CGPoint)fp8#> zoomLevel:<#(float)fp16#> animationType:<#(int)fp20#>]

There are numerous other selectors in the API, and I'll point out interesting ones once I get to know the API better. In future posts I would like to demonstrate how to change the tiling behaviour (caching more tiles) and how to integrate advanced map features, as well as starting a Street View based on the current map coordinates.

Monday 17 November 2008

Loading HTML from the Main App Bundle

To load a static HTML from the main app bundle (useful to initialize web views in some way) use the following code:


//fakes a URL
NSString * urlStr = @"http://myServer/mypage.html";
// loads the actual HTML
NSString * html = [NSString stringWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:@"phone" ofType:@"html"]];
// loads and displays the page
[thisWebView loadHTMLString:html baseURL:[NSURL URLWithString: urlStr]];

Calling Nonatomic Properties in the Context of the Main Thread

In multithreaded applications, it may sometimes be helpful to call nonatomic properties in the context of the main thread. This is especially relevant if you want to update views (which run in the main thread) from other threads, i.e. a server accepting commands that change the properties of some view of the app.

Luckily, NSObject implements just such a function, which is called performSelectorOnMainThread, that lets you call the selector of an object in the main thread's context:


[myView performSelectorOnMainThread: @selector(update:) withObject: updateItems waitUntilDone: YES];


It even has the option to let the calling thread wait until the call has been completed!

Tuesday 11 November 2008

iPhone Tech Talk at HU-Berlin

I visited the iPhone Tech Talk at HU Berlin yesterday. It was quite interesting, altough I would have liked the speakers to go into more detail about certain subjects (i.e. layer manipulation). For a (somewhat) experienced iPhone developer like me, the event rather much of a promotional, commercial character and was less serious about conveying in-depth technical information.

Anyhow, for those who are interested, here are my rough notes covering some important things that were said:


== Session: Iphone Programming ==

- Don't implement a quit button (pretty obvious).
- Sandbox (limited directory access):
/Documents
/tmp
/Library/Caches
- External Data:
- contacts
- system settings
- voicemail
- photos
- other app data
- Exceptions in Objective-C++
- unified exception model (@try...@catch) works both with c++ and objective-c
- Objective-C memory management:
- retain / release pattern (reference counting)
- first initialisation sets reference counter to 1 (no extra retain needed)
- -autorelease message: sends -release at a later moment (using autoreleasepool)

myString = [[NSString alloc] initWith...] -> retain count 1
myString = [NSString stringWith...] -> utility method, retain count 0 (gets autoreleased at end of method)
- Objective-C setters / getters in Objective-C 2.0
- "properties" control storage semantics
- e.g. @property(readwrite) float speed;
- "readwrite" only one of many keywords, e.g. "atomic, nonatomic, readonly..."
- in implementation file: @synthesize p1,p2,... ; generates getter/setter code implicitly
- Objective-C categories: expand functionality at runtime (similar to protocols)
- @implementation NSString (myExtensions) ...
- Foundation Bundles -> special folders containing the data associated with your app
- special apis provide access to the bundle (NSBundle class)
- bundles are read-only on iPhone (because of code-signing)
- Application Design Patterns
- MVC
- Model: Foundation
- View: UIKit
- Controller: UIKit View Controllers (provide basic functionality)
- Target-Action: (controls can be re-used for different actions)
Control -> Target -> Object
-> Action -> Selector
- Notifications: Notification -> Notification Center --> Observers
- i.e. finishedPlaying Notification when movie terminated
- Delegation: Application Life Cycle:
- UIApplication instantiation, Main NIB loaded, Main Window created
- Application Delegate: this is the user's code that gets called after UIapplication has started (your app)
- benefit: no subclassing necessary, as delegate extends functionality
- app delegate hooked up in interface builder
- other UI classes relying on delegates: pickers, table views, etc...


== Session: UIKit App Development ==
- View controllers:
- manage currenct screen content
- handle user interaction, key SDK concept
- two major types:
- yours -> present per-screen content
- from apple -> manage multiple screens (i.e. switched by tab-bar controller)
- rarely subclassed (customization throught delegation)
- Key Methods: loadView, viewDidLoad, viewWillAppear, viewDidAppear
- write in Xcode: view controllers
- layout in interf. builder: views

- Apple view controllers:
- navigation controller: provides navigation bar on top of window
- stack-based naviagation: manages stack of view controllers, easy to customize...

- Tab bar controllers:
- "flat" navigation, no hierarchy
- provides "tab bar" on the bottom of the device
- different views on the same data or show different parts of the app (i.e. clock app)
- only five icons shown at a time, but more can be added on a separate screen (accessed via the "more" button)
- tab icons: developer provided only monochrome image with apha -> appropriate colors are provided by framework

- Other special views:
- tool bars:
- icons don't retain a title
- icons don't remain highlighted
- used for one-shot actions, often to present follow-up modal or alert views (by default, they slide up from the bottom, to indicate that they are temporary, vs. "navigation" affordance by left-right movement)
- table views:
- tableview delegate + data source
- table view cells are re-usable: already instantiated cells get re-used once the scroll by. They shouldn't be deleted and re-instantiated.
- Autorotation + Autoresizing maks can be specified with interface builder
- Size of the screen can change when incoming call arrives, or when keyboard appears -> well-behaved apps handle these conditions
- memory warning: -didReceiveMemoryWarning
- release non-critical objects ASAP
- initialize application lazily

- Animations:

- implement UIView change properties by wrapping with UIAnimation! --> very nice feature. setup animation ... commit animation.
- animation finished callback called when animation is done

- Text Display:
- UILabel
- UIWebView: can display HTML, PDF, Word files
- NSStringDrawing

Touch Screen:

- UITouch: information per touch

- UIEvent: collects all touch events
- allTouches, touchesForWindow, etc..
- myview.multipleTouchEnabled = YES;
- "Touches" sample code on developer connection

- Accelerometer:
- x axis is inverted (runs from right to left)
- interface orientation
- device orientation
- analog user input

- raw accelerometer data:
UIAccelerometer accel [uiaccelerometer sharedAccelerometer];
accel.updateInterval = 1 / f; (f = 1 - 100hz)
accel.delegate = self; -> delivery begins immediately

- filtering data:
- low-pass
- isolates current acceleration, discrete inputs --> bubbleLevel
- high-pass filter: isolates instantaneous movement
- used to find shakes and oscillations
-> accelerometerGraph

Session: Optimizing & Profiling

- Tools: Instruments (memory footprint, leak detection, cpu usage), Shark (profiling of method calls -> doesn't work that well yet)
- static memory: -mthumb compiler flag reduces to 16-bit ARM instruction subset (35% savings in size)
- PNGs are optimized
- plists are converte to compact binary format by Xcode -> use plists for structured data files
- Dynamic memory:
- autoreleasing is is expensive: try to do it manually (avoid conveniece Methods)
- use local autorelease pools to prevent object accumulation
- drain local autorelease pools periodically
- declare properties as nonatomic -> access is 10 times faster, but not thread safe
- avoid leaks, use Instruments
- Drawing Envirnment:
- use UIKit view animations when possible (very optimized)
- mark views as opaque to improve performa



Thursday 9 October 2008

Using the unofficial headers with the official SDK

For advanced applications, using the "private" frameworks of the iPhone SDK can be useful, for instance if you want to create a framebuffer for video playback, which isn't normally allowed.

The iphwn.org Wiki has a nice howto on including the headers from the unofficial toolchain in your "official" project. http://wikee.iphwn.org/howto:using_sdk_with_toolchain_headers.

Note that copying their method entirely breaks compatibility to the official framework. I'm working on how to only use part of the unofficial tools for my project.

Here are the modified "other-c-flags" which need to be added to the project in Xcode, update to iPhone 2.0:

-I/Developer/SDKs/iPhoneOS.sdk/Versions/iPhoneOS2.0.sdk/include -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/usr/include -I/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/gcc/arm-apple-darwin9/4.0.1/include -F/System/Library/Frameworks -F/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/System/Library/Frameworks -F/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/System/Library/PrivateFrameworks -DMAC_OS_X_VERSION_MAX_ALLOWED=1050

Monday 6 October 2008

Using iPhone Developer Program (Standard) with more then one developer

We only have the standard edition of the iPhone developer program. So to get another developer up and running with another machine, some trickery needs to be applied, i.e. copying the private key and the certificate over to the other machine and doing some configuration.

Furtunately, MacRumors.com has a useful solution to this problem:

Provisioning now becomes simple. You need one Provisioning Profile for development and another one for distribution. One and only one of each type of provisioning profile. Each profile uses your one App ID. Put your development provisioning profile in ~/Library/MobileDevices/Provisions. Start XCODE and drag your distribution provisioning profiles to the xcode icon once it is running. XCode does something to distribution profiles (renames them at least) and puts them for you in ~/Library/MobileDevices/Provisioning Profiles/. But you cannot drag your distribution profiles into this folder directly.

That seemed to do it for me. The only thing I did different was put my .mobileprovision file in ~/Library/MobileDevices/Provisioning Profiles/ and drag it into XCode from there. No idea why that's necesary, but its working now
The last sentence seemed to do the trick for my colleague!

Compiling Unix Libraries

The iPhone has a Unix subsystem, so it shouldn't be too hard to port unix libraries to the device, so I assumed.

It turns out that it is not that trivial, as some tweaks are needed to properly compile third-party code for the device.

This Blog presents an excellent solution to the problem - enabling the use of the libraries both on the emulator and on the device, compiling with the official SDK.