I have been working on the iOS platform for two years now. I really enjoy it. I like the focus on fluidity and good user experience championed by Apple but I also like the engineering challenges that programming apps offers. Here is a whirlwind tour of what difficulties you could expect when beginning to program on iOS.
The first constraint that you have to take into account is this famous focus on fluidity. As I once saw on Twitter, the rule is "60fps or GTFO" (I think this was from @flyosity). Apple has set a standard of smoothness through all their apps (OK, almost all). The scrolling speed and responsiveness of the iOS platform is still globally a notch above everything else. This is seen as a given and you will see most of your users tap impatiently on their device if your app freezes more than half a second. And freezing while scrolling will most probably decrease your average number of stars on the app store.
To get fluidity, the recipe is well known: there is one main thread in charge of updating the UI of your apps. You just need to avoid doing input/output (disk or network) and expensive computations on this thread that would cause UI freezes.
Put differently, you have to make your program concurrent: launching the expensive tasks in background and waiting for them to callback. Problem: concurrency is hard, PhD thesis level hard. It is very difficult to think about a concurrent program because you lose the strict sequentiality, and you can easily get in troubles when modifying the same memory space through different threads.
The main problem here is that if you forget to go back to the main thread to update your UI at some point, you will experience crashes in your app (because UIKit, the graphical framework of Apple, is not thread-safe), but as always with concurrency, these crashes might not always happen, and be hard to reproduce in the debugging environment, because setting a breakpoint for example will change the sequence of events.
The matter is further complicated by the fact that if you use Core Data (and if you need structured data storage, this is the way), it brings its own constraints. Basically, you cannot manipulate a ManagedObject (the base data class of Core Data) on another thread than the one where it was created without risks of crashes. Happily, iOS offers some nice ways of distributing your work over multiple threads, but this brings me to the next difficulty of the iOS platform.
More than one way to do it
The Perl motto applies very well to iOS: "There's more than one way to do it". The technologies used in iOS date back to NeXTSTEP in 1989 and it shows, because you still find in the libraries the traces of this long history, with lots of variations in the way to do things over time. You often find very similar implementations of the same concepts, one in Objective-C and the other in a pure C API (UIFont vs CTFont, for example), with naturally some discrepancies. To get back to threads for example, you have at least 4 different ways to launch a task on a background thread:
- using NSObject's
- using NSThread
- using the Grand Central Dispatch C API
- using NSOperation introduced in iOS4
How do you know which one you should use? As a rule of thumb, you should use the highest level of abstraction that suits your needs, but this brings us to the next difficulty of iOS.
You will have to navigate the docs to find out which way is the right one in your case. Unfortunately, Apple's documentation is not easy for the beginners. As I read somewhere that I cannot find back now: the documentation is quite clear once you have understood the subject matter, meaning that everything is explained, but not always in the most straightforward manner, and sometimes, information is hidden in suprising spots. Notably, when lost, you should hunt first example Xcode projects provided by Apple to illustrate the use of some APIs, but beware, some of them are seriously outdated, and then you should look at WWWDC videos. Honestly, it was quite infurating for me to discover that some information is only available in video format (about Core Data contexts merging for example) which is obviously not very googlable (especially since this material is in fact behind a login wall).
Another thing that makes iOS programming difficult is that you cannot count on stable network connections (but this applies to all mobile platforms, obviously). Every network request can fail due to the user movement. This is quite different from what happens when you do front end development or server development, where most connections are quite stable. You have to provide graceful behaviours for so much more types of problems.
What makes this even more important is that, compared to web apps, where users have been long taught to do a refresh when something seems to freeze, on mobile, users are not used to relaunch their apps in case of problems (and happily so). If your app is stuck in a bad state with no way for the user to get back in a better situation, there is a good chance that he will simply uninstall the app.
Other difficulties arise when you need to offer some functionalities offline (think about people using your app on the plane). This brings synchronization problems, that as a general rule, are as hard as concurrency problems. Nothing strictly related to iOS, but still a major cause of headaches.
Memory management used to be a major pain point in objective-c, but it has gotten a lot better since the introduction of automatic reference counting in 2011. You still have to understand what will be kept in memory (everything for which your keep a strong pointer), and you will probably have to understand at some point how ARC behaves when using blocks, but over is the time where you spent hours chasing the superfluous
release in your app.
Fighting the system
The degree of liberty offered in iOS to developers is way smaller than what is offered on Android. For example, you are not allowed to keep a daemon running in background when your app is minimized (to download files for example). If you have something like that to do, you have at most 10 minutes to execute them after the user minimized your app. Similarly, you are not allowed to keep a connection open to a server passively either, unless you are a VOIP app. There are also constraints to access the address book of users, keeping the GPS active, and so on, and so forth.
Most of these constraints stems from Apple's intent to keep the user experience pristine from bad developers experimentations, but that does not mean that these constraints cannot be frustrating and that finding workarounds is easy.
App Layout and Text manipulation
There is nothing similar to the flowing layout of HTML in iOS. If you want for example a UI with a paragraph of text and a button just underneath, you will have to compute the height of the text, and put the button at the right place. This can seem particulary brutal for web developers, and be hard to explain to customers and managers accustomed to the relative plasticity of html and css.
Furthermore, this may not apply to all types of apps, but if you need pixel perfect text manipulation, like I did for checkthis, you are in for lots of troubles. Either you have text editing using UITextview but without too much control on things like line height and stylings used for links, either, you have the full control offered by CoreText but without any editing capacities. You have to program all editing by yourself. I must say that there is hope on this front, with this (paying) component, but I did not test it. If you do not need text edition, but just more control over the layout and styling, you can use TTTAttributedLabel.
For layouting text, lots of people resort to HTML and CSS in UIWebView but this can get a bit unholy and offers challenge on its own due to the asynchronous rendering of webviews. I will not dive too much into the controversy of Native vs Web Apps, but let me just state that most popular apps on the App Store are mainly native.
This might be obvious to some, but the fact that you cannot access the sources of the UIKit framework, or other important parts of the iOS platform can turn into a real problem when you hit a hard to understand bug. I lost count of the number of time I read on Twitter something along the lines of : "Apple's component x does not do expected behaviour Y, please give me back the days lost trying to understand." and I have been a victim numerous times too. The platform is not especially buggy, but not having access to the source complexifies debugging when needed.
As a side note, the quality of iOS open source varies wildly and there are big surprising holes that are not covered, like for example having a good Twitter connection library that would take into account the latest additions of the Social Framework, while fallbacking to classic in-browser-oauth when on iOS4-5 or when the user did not setup his accounts. I am not complaining about anyone's work here, just observing.
In conclusion, iOS is at the same time one of the most rewarding and challenging platform that I had to work with. There are lots of constraints to take into account but happily, I find the tooling extremely good. Instruments and Xcode are first rate tools. They obviously have their own quirks, but compared to Eclipse or Visual Studio, they fare very well.
On the rewarding side, Apple's customers are using tons of apps that they will take wherever they go, and this is the most personnal computing that I know of. Furthermore, there is a lot of demand for competent mobile developers these days and mobile is where the double digit growth is. So, if you are on the fence, I would encourage you to take the plunge into iOS development.