This is a post for every iPhone/iPad developer. Every day, we try to use “best practices” when writing code, and building apps.
We make apps that:
- …fail gracefully (instead of crashing)
- …re-use code (reducing the number of bugs)
- …re-use code (increasing the speed of development/new features/fixes for old bugs)
- …we test extensively (using the Simulator to rapidly check and fix bugs before users see them)
- …we test extensively (purchasing one of every iPhone/iPad etc to guarantee it works for everyone)
There’s a lot of great stuff in iOS to help with this. The standard-libraries Apple wrote for iOS 2 / iOS 3 are exceptional in quality and design.
And yet … while Apple’s library team has bent over backwards to help developers, it feels like the Xcode team sneaks up behind developers and stabs them in the back. They do it in low-level tools and changes that most ObjectiveC programmers don’t understand or care about. These seem far removed from normal coding. But they influence everything we do – right up to the recent “Xcode won’t allow you to submit your App to the App Store” bug. These are the silent quality-destroyer that slows down development every day.
Developers suck it down – Apple provides no channel for acknowledging or reporting on this stuff (even their bug system is locked-down and private). It’s time to shine some light on Apple’s shamefully bad tools…
Apple does not allow developers to re-use or share their code via dynamic libraries – most of what you see in code-re-use is due to hacks using Static libs that developers have built to workaround Apple.
To be clear: Dynamic libraries have been Best Practice for decades; even Apple has been telling developers for years to use Dynamic libs across the board (read the OS X documentation).
When iOS came out, no apps were allowed to run “dynamic” code. This was a well-intentioned (but perhaps short-sighted) decision that Apple was later forced to reverse. But they kept the (now meaningless) ban on developers using the core language features of dynamic linking.
Thanks to Apple, we can more easily write virus/trojan code that sidesteps Apple’s security checks (by running scripted code, which is now “allowed”) than we can write legitimate code that does not (Apple screens it when you upload to the App Store).
Workaround1: Static linking of static libraries
Apple has consistently told developers to use “Frameworks”, Apple’s proprietary system for managing libraries that abstracts the Dynamic/Static difference. Frameworks are hugely valuable and speed up development while reducing bugs. I love Frameworks. They visibly reduce the stress of your team – it’s hard to exaggerate what a positive difference they can make.
But from day one, Apple blocked iOS developers from using this feature, and have never allowed us to use it. Anecdotally, the reason given was “frameworks can (optionally) be Dynamic, and dynamic linking isn’t allowed”.
This is (cow)(excrement). The community has already proved there is no reason for Apple to ban Frameworks from iOS. Instead of a trivial change on Apple’s side, developers have to jump through hoops and hacks to un-break Xcode.
Continuing in this vein, Apple won’t allow iOS developers to use Bundles – which are nothing more than ZIPped folders of ordinary files!. Frameworks made Bundles “optional”; without Frameworks, Bundles are “required”, but for the last 3 years, Apple has actively prevented iOS developers from using them.
Again, if you doubt this, you can use the commmunity-authored workarounds that work (after you jump through all the hoops). Apple won’t explain their actions, but again: this appears to show there’s no reason for Apple to block developers from this feature.
Workaround2: Dynamic linking of Static Libraries
25 years ago (this is how behind the curve Apple is!), before dynamic libraries were viable, there was a solution with Static Libraries. The toolchain is supposed to be “intelligent” (all of them except Apple’s) and only link static libs where necessary.
Apple is different; Xcode cannot detect that 1==1, even when its own tools tell it this is the case. Xcode then blocks your code from building, for no reason at all, pushing developers through more obscure hoops – or to just give up, stop re-using code, and instead copy/paste duplicate it. Causing many, many bugs in the process.
Here’s a post from 2010 where someone figured out the problem and some code Apple could use to fix it. This still has not been fixed. As one commenter put it:
“…I’ve been doing this kind of thing for 29 years, and yet in 2011 Apple cant get linking libraries right? Its a waste of our time.”
Apple has real problems with this, it’s no joke – when the iPhone4s came out, it broke Apple’s compilation everywhere for all apps, in the live version of their tools, because of this same bug (combined with another bug, and Apple apparently forgetting to test their own tools). Apple fixed the “other” bug, but ignored this one. So we’re still suffering it, in 2013/2014…
Corollary3: Static combining of static libraries
Three years ago, Apple removed the feature of Universal libraries. There was a footnote at the time saying they’d done this, but offering no explanation.
Since then, Apple seems to have made no effort to bring this back. Even though it’s needed by every non-trivial project (Of the last 20 projects I’ve worked on, … 20 of them have needed this feature). A bunch of iOS developers wrote scripts you can add to Xcode that re-add this feature. This script is used in many apps. It’s a pain to maintain – Apple keeps breaking it – but if we’re able to make this perfectly-working “hack”, why can’t Apple re-enable the feature? What possible reason is there to hurt developers like this?
My best guess is that the root problems behind the previous bug above (whereby Apple’s linker is so stupid it can’t handle multiple architectures, even though it’s built on a linker that can) are the reason Apple removed this too.
However, Since the launch of the iPhone4, Apple has been creating Universal libraries on all iOS builds. And it doesn’t always work – as noted above, Apple’s crappy tools keep causing problems here. First on iPhone 4, then 4S/5. It’s like they spend 2 years building new hardware, but forget to let the Xcode team test it. WTF?
Of course, if they just fixed Xcode itself, these problems would go away…
This post is a rant. Unashamed, frustrated, (hopefully) coherent. I know Apple won’t do anything to fix this – if they cared, they’ve had more than 3 years to fix most of the above problems. But it makes ongoing iOS development on medium-to-large projects a never-ending nightmare of shitty, broken tools that repeatedly stab you in the back.
As one friend put it recently:
“I had no idea iOS development was so primitive. Apple owns the code, the tools, the hardware, and the OS. I thought it would all work together! But it doesn’t. Right now, it looks to me like it would be cheaper and faster to use Unity for everything. .Net is a robust and widely-used platform”
Tragically, he’s got a good point. It’s amazing that Apple’s investment in tools is so dire that a multi-billion-dollar company – that has total control of the environment – can’t keep up with a tiny, 7-year-old startup that has to work with every platform, and has no control over anything.
Now, if the Unity guys can just get that forever-promised, never-delivered UnityGUI system delivered … I may walk away from iOS forever. Except to hit the “publish for App Store” button in Unity. That’s a road that Apple should be terrified of: developers leaving the ecosystem and going cross-platform. Because once you take that first step out of the walled garden, every step that follows is easier.