Events have conspired against me and I find myself writing an iOS
app. Off the back of some relatively complete android work, I was
interested to see how the platform compared.
First steps
After the gigantic pain of upgrading a dual boot Leopard/Ubuntu
macbook to Mountain Lion, installing XCode was relatively trivial
(albeit I had to enter my password roughly five or six hundred more
times than I’d hoped). I dived straight in hoping I would soon emerge
with some useful knowledge; you will have to be the judge. Onward!
Objective C isn’t actually that weird
Once you figure out that Objective-C is seriously old (possibly even
as old as C++
!), some of its idiosyncrasies start to seem a little less odd.
Boolean is YES | NO
One assumes because originally, this was a macro based implementation
(C doesn’t have a boolean type; or, at least, it didn’t until C99,
where a standard macro implementation appeared, I think). This
stackoverflow
answer
adds some colour.
There are no constructors
…and this has lead to a great disturbance in the force, with two
idiomatic initialization methods.
-
alloc then init
[[NDHSomeType alloc] initWithParams:params]
which is tidy, but bad luck if you forget the init.
-
class methods that wrap this up for you
+(NDHSomeType *) initWithParams:(NDHParams *)params
which is tidier still, but cannot actually prevent someone still doing
[NDHSomeType alloc]
This is very annoying as it hampers our ability to create truly
immutable objects.
There are no namespaces
As such, XCode forces you to pick a three letter prefix for all of
your class names. For shame.
Implementation hiding is a feature
This is probably my favourite thing so far. Given a Foo.h
that contains
@interface Foo @property NSString * bar; @end
One can, in the implementation file, Foo.m
, add further
functions and properties as necessary, which are hidden from calling
clients, thus:
@interface Foo() @property NSString * hiddenFromClientsButVisibleInFoo @end
This reminds me of the well used C++
pImpl idiom (see
this
post
for a simple example), which I’m a big fan of; as such I’m pleased
this exists in objective C too!
id
This appears to be the objective C equivalent of void
. Objective C is not that type friendly – collections are
*
not generic, and calling any method you like on an id
is
only a compiler warning, not an error.
That said, one can, in a function definition, suggest that the actual
object that is eventually passed adhere to one or more “protocols”,
thus:
@protocol NDHStringListener -(void) onString:(NSString *) someString @end @interface NDHStringTransmitter -(void) transmitString:(NSString *) someString toListener:(id<NDHStringListener>) listener; @end
Now we just need a class that adheres to this protocol:
@interface NDHStringDisplayer : NSObject<NDHStringListener> @end
Passing instances of NDHStringDisplayer
to
NDHStringTransmitter
is now fine. Annoyingly, passing
instances of objects that don’t declare protocol adherence is still
only a warning; although I assume one can configure the build process
to make it an error.
Blocks
This is how objective C deals with anonymous functions. The
documentation
covers how this works, but essentially, things aren’t too bad; blocks
are not too dissimilar from C++11′s lambda.
int (^addOne)(int someInt) = ^{ return 1 + someInt; }; int five = addOne(4);
a block named
addOne
, and an invocation of it.
One slight annoyance – I think all blocks are passed to other functions as id
; there’s no way to say that you expect a block that takes an int and returns another, say.
Available APIs
Asynchronous execution
This is probably the most important part of the platform from my
perspective – the app I want to write does a lot of I/O, so making
sure this happens away from the UI thread is important.
iOS 4 introduced grand central dispatch (gcd), which seems highly
sensible. It rather provokes the question “What the hell did people do
before?”, but there you go. The abstractions on top of this don’t seem
as rich as android’s AsyncTask
framework, but that may be
because the presence of blocks makes writing your own abstraction much
simpler.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NDHResult * result = [fn call]; dispatch_async(dispatch_get_main_queue(), ^{ [result passTo:receiver]; }); });
An example of ‘dispatching’ a block to be executed in the
background. On completion, a further block is ‘dispatched’ back to
the main (UI) thread.
UI framework
The storyboarding provided in XCode makes it, I would guess, much
easier for a lay person to get going in creating a layout. Android
does have tools for this, but they are considerably more rudimentary,
and any serious app will require some fiddling with the underlying
XML.
Interestingly, storyboards seem to be relatively new, with many of the
older iOS code examples still using a disparate collection of ‘xib’
files to create single views that are then linked together
programmatically. As a beginner coming to the platform, this is
somewhat confusing; which way is the right way?
I want to write quite a rich app, and I am finding that the storyboard
is a bit of a crutch; I’m much happier with android’s HTML like layout
model where I don’t really need to learn a complicated GUI tool in
order to create a GUI! I suspect I may end up switching to the old
style of xibs and doing the work the storyboard is doing in a more
obvious fashion.
HTTP
Well, the provided framework is…quite low level; it feels quite like
Java
‘s HttpURLConnection
(HUC), in that all
it really wants to do is fling a byte array response at you with a few
extra pieces of response metadata. This is, in fact, absolutely fine,
as the included json library is perfectly capable of consuming that.
Predominantly, it also wants to behave asynchronously; I’d be
interested to know if it’s powered by NIO underneath or a real
blocking thread. (I am being evil and doing things synchronously on a
background thread anyway, mwahaha.)
One huge upside is the lack of exceptions – each interaction may call
you back with an NSError *
or the resulting NSData
depending on success (synchronous methods ask for an output
*
parameter in the form of an NSError **
). This is way
better than the clusterfuck of IOException
sprinkled all
over the Java
equivalent.
Side note: one could compare the iOS HTTP library to Apache
HttpClient, but that would be somewhat unfair, given the complete mess
that android has made of deploying it, and their recommendation to use
the HUC API for new apps.
Documentation and process
In general the API documentation is good – one can click through to
see the provided header files and a brief google gets you to the
equivalent web pages.
Some areas where Android is ahead:
-
StackOverflow answers are much better
-
Available examples tend to be richer, and more up to date …I
suspect this is mostly because the “right” way of doing things has
moved quite a long way on the Apple side, so it’s less clear what
the idiomatic way of doing things is to the community at large. -
Getting the app on to a real device is trivial for Android, where on
iPhone, it’s a nine step marathon that you have to pay them $99 to
participate in; this is not at all developer friendly and reminds
me precisely why I don’t use iOS devices more generally.
XCode
All I will say is this: within half an hour I was googling to see if
IntelliJ supported iOS projects yet. I shall have to give AppCode a try.