My Android app for Galaxy Zoo is doing pretty well. Creating it gave me a chance to learn Android development quite thoroughly. So I thought I’d do the same for iOS, with Objective-C. The Galaxy Zoo iPhone app is now mostly done, though it’s only available via TestFlight for now. Please send me your Apple ID (usually your email address) if you’d like to try it.
Over the years, I didn’t much believe the reports of Apple’s APIs, tools, and documentation being so wonderful. But I had hoped things would be better. Android’s API and documentation can be frustrating, but developing for iOS feels worse, with rather primitive tools. It’s still doable, but I can’t think of anything about it that I prefer to Android development.
This is a rough collection of rants, so I reserve the right to revise my opinion when I have gained more complete understanding.
Learning Objective-C was not too difficult, though I still find its syntax and terminology arbitrarily different and often obstructive. Watching all of Stanford’s “Developing iOS 7 Apps for iPhone and iPad” course (on iTunes here too) helped me gradually get used to Objective C, XCode, and Apple’s *Kit APIs.
I chose to start with Objective-C rather than Swift, just so I’d have a chance to learn it and to avoid any problems caused by Swift still being fairly new. I plan to convert my code to Swift soon as its gradually becoming the default language for iOS development. Unfortunately it looks like Swift inherits most of Objective-C’s weird features.
Whereas in Java or C++, you would call a method on an instance like this:
SomeResult *someresult = something.somemethod(arg1, arg2);
in Objective-C, you’d send a message (not call a method) to an instance, like this:
SomeResult *someresult = [something somemethod:arg1 witharg2:arg2];
And if something is nil (null) then, unlike C++ or Java, there will be no runtime crash or exception – you’ll just get a null result. So you don’t need to check for nulls unless you really need the method to be called, though this leads to all kinds of extra implicit paths through your code. I secretly like this, but it is of course madness.
Users of C++ or Java will also be shocked at how it’s normal in Objective-C to add API to already-defined classes instead of providing the API via derived classes or helper methods. For instance, when using the (not from Apple) AFNetworking library, you can #import “UIImageView+AFNetworking.h” to add methods (messages) such as
setImageWithURLRequest to the regular UIImageView class.
XCode is overly simple when it comes to basic code editing and debugging. I was amazed that I couldn’t just click on an exception’s backtrace to go to the relevant line of code. And I really missed the refactoring features in Android Studio or Eclipse.
XCode is not intuitive, forcing you to learn where to click and when, instead of learning how some structured code works. For instance, you need to know about the magic Ctrl-drag to access UI controls in your code, to respond to UI events from those UI controls. Embedding your views into tab bars and navigation views is similarly obscure.
Nothing has frustrated me more than Auto Layout in iOS. Amazingly, iOS had no real automatic layout until iOS 6 in 2012, and I don’t think it was really usable until iOS 7 in 2013. And developers still needed separate layouts (Storyboards) for iPhone and iPad versions of their apps until iOS 8 in 2014.
Auto layout seems to be a matter of playing with:
- Constraints: You can add constraints, for instance to say that a child view (widget, control) should be the same width as another view , or that it should have a certain size of margin between itself and the leading (left) edge of its container. The XCode UI makes it really hard to see what constraints exist and the XML is obfuscated, so this is really difficult. You still need to specify positions and width/height for all your views, even if they would be changed by the auto layout, so you inevitably have to keep dealing with XCode’s warnings about the “frame” not being the same as it would be at runtime.
- Content Hugging (vertical or horizontal): A high value stops the view from being made larger, instead “hugging” its content (such as text). I dislike this terminology particularly.
- Compression Resistance (vertical or horizontal): A high value stops the view from being made smaller.
Content hugging and compression resistance are numeric values, so your layout tends to become littered with arbitrary values such as 100, 250, or 1000, as you try to make things work, with very little sense of overview of the whole layout.
I much prefer the automatic layout systems used in GTK+ and Android, where it’s mostly just a matter of using parent layout containers and telling them how to arrange their children. Android’s layout system is often cryptic, compared to GTK+’s simplicity, but the layout XML is readable so it’s fairly easy to try things out. Stackoverflow answers about iOS autolayout are all about where you should click in various versions of XCode, but the answers about Android layouts can just show XML samples.
Android child fragments can be difficult, but I eventually worked things out. In iOS/XCode still don’t have a satisfactory way to auto layout child containers that contain child views.
CoreData seems to be a way to access a SQL-like database using generated classes. For instance. I find the manual code generation quite awkward, but I suppose it works. Most of my difficulties were to do with using CoreData with RestKit. But I eventually found its saveToPersistentStore() method to actually store the data reliably.
I’ve also missed having an equivalent for Android’s SyncAdapter, though I have not yet found the same UI performance problems that made it so necessary on Android.
I can understand Apple’s insistence on reviewing all app uploads to their app store. But it’s annoying that every version of private beta tests have to be approved too.And
To let someone beta test your app via TestFlight, you need to know their Apple ID and add it manually in the iTunes Connect website. In comparison, with Google’s Open Beta Testing for Android, you can just publish a URL that lets people opt in themselves.
And as far as I can tell, users don’t get any notification when you release a new beta version. So your old testers generally don’t even install the new version until you’ve bugged them individually to do so.