14

There are elements like UITableViews, UINavigationBars that have a different style on iOS 7.

This style is determined at run time, since those classes are implemented on UIKit, and UIKit is linked with your application dynamically at runtime, not statically at compile time.

So one would think that any app run on iOS 7 would have those elements look the way they look on iOS 7. However, they keep the same style they used to have on iOS 6, until you compile with the iOS 7 SDK. Except for some of them (like UIAlertView or UIMenuController)

My only explanation for this is that they do something kind of like this:

#define SDKApplicationWasLinkedAgainst ...
if (SDKApplicationWasLinkedAgainst < 7.0)
    ...
else
    ...

This is obviously really cumbersome, cause they need to keep maintaining a lot of old code. So I'm curious, is this really what is going on under the hood? What am I missing?

Javier Soto
  • 4,840
  • 4
  • 26
  • 46
  • 5
    @Unicorn: True, however he isn't asking about anything that is specific to iOS 7 that would be covered by the NDA. This question could apply to **any** two versions of iOS. – lnafziger Jul 10 '13 at 19:09
  • 2
    Unfortunately, unless you are a coder at Apple, you can't really answer the question of how **Apple** does it. You may get some ideas on *a way* that **you** could do it if you reword your question though. – lnafziger Jul 10 '13 at 19:11
  • 2
    This can actually be answered even if you don't work at Apple, and it won't be an opinion: a college of mine found out how they do it doing some disassembly. – Javier Soto Aug 13 '13 at 19:31
  • 2
    While that is great and all, why not provide an answer then? ;-) – lnafziger Aug 13 '13 at 23:37

3 Answers3

9

Without going too much into NDA'd territory, I'd just like to state that yes, they are conditionalizing appearance and behavior based off of the result from the following call:

_UIApplicationUsesLegacyUI()

This function, in turn, makes a call to GSApplicationUsesLegacyUI(), which I presume returns a result based off of the version of the linked UIKit.

This means that yes, they are conditionalizing parts of UIKit for legacy. Not sure that's a good thing, but that's what they decided to do.

Léo Natan
  • 56,823
  • 9
  • 150
  • 195
sudo rm -rf
  • 29,408
  • 19
  • 102
  • 161
4

My bet is that they use framework compatibility versions.

Each time you compile your app, your app is linked against an specific framework, with compatibility version and current version. You can see those numbers if you run otool -L YourApp.app/YourApp. For example, for an application compiled some time ago I obtained this:

/System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 751.58.0)
/System/Library/Frameworks/UIKit.framework/UIKit (compatibility version 1.0.0, current version 1500.0.0)

As you can see the full path of the UIKit framework is stored in the Mach-O binary, along a couple of versions (and specially the version I compiled against at that moment).

I suppose that iOS 7 will have both UIKit version included: the one from iOS6 marked with the corresponding version and saying compatibility from 1.0.0, and the one from iOS7 marked as compatible with something higher than 1500.0.0 (I don’t know if that’s the number for iOS 6.1.3, but you get the idea).

When your iOS6 binary is loaded, its library dependencies are read by dyld and resolved, because you were compiled saying current version 1500.0.0, and the library for iOS 7 says compatibility version 1501.0.0, you will be linked against the library for iOS 6.

Since a framework is also a bundle, all the resources are perfectly contained, and will be used only by the right version, and that’s how the different visual elements will look different if you compile against iOS 6 SDK or iOS 7 SDK.

I might be wrong, but I simply hope they are not using the code technique you propose, because that will be a crappy code base to maintain.

yonosoytu
  • 3,319
  • 1
  • 17
  • 23
  • I don't think that iOS comes with multiple versions of the same framework. In your example, the 1501.0.0 version is backward compatible to the 1500.0.0 version. But as you correctly said, the version number that the app was linked against is recorded in the binary, so that could be checked at runtime. – Martin R Jul 10 '13 at 20:07
  • This still wouldn't explain why certain classes do have the new look (e.g. `UIAlertView`) – Javier Soto Jul 10 '13 at 20:32
  • @MartinR: checking at runtime is possible, but I think double binaries are easy to deal with. If I had to do what Apple has to do during transition times, I will choose to not do those checks in runtime. – yonosoytu Jul 10 '13 at 21:05
  • @JavierSoto: if you have two library binaries and two library resources it can be explained easily. iOS6-linked apps run and use resources from one library, iOS7 use the other resources. – yonosoytu Jul 10 '13 at 21:11
  • Again, why does `UIAlertView` have the new style then? if it using the old UIKit binary. – Javier Soto Jul 10 '13 at 21:14
  • Just a stab in the dark, but could it be that UIAlertView is using XPC? – Dave Lee Jul 11 '13 at 17:34
  • Sorry, I did understood `UIAlertView` showed the old interface. Well, an explanation is that they haven’t include just the same version as in 6.1.3, but something in the middle which does the new alerts and action views. As far as I remember those are in their own `UIWindow`, so they will not clash with anything the user is doing in its own window. – yonosoytu Jul 11 '13 at 18:27
-1

I can't be certain, but this is one guess about how it is done. Because they know what SDK version your app was linked against, they version out the framework on iOS 7 devices. So there is a hierarchy on the filesystem along the lines of /.../iPhoneOS6.1.sdk/.../Frameworks/UIKit. Then when it loads your app, they can just set the search path for libraries to point to whichever SDK your app was linked against.

This is how Xcode does it right now. Inside the Developer directory inside the Xcode package is an SDKs directory, which, in turn, contains all the different SDKs to link against.

Streeter
  • 556
  • 4
  • 22
  • This sounds like a possible idea, but can't be because there are some things that do look different. Like `UIActionSheet`, `UIAlertView`, `UIMenuController`... – Javier Soto Jul 10 '13 at 19:06
  • In that case, iOS 7 devices could update the look of previous SDKs. There is nothing that says that version of the OS can't update the old SDKs at all. This is how the OS can update the SDK for minor releases (6.0.1, 6.0.2, etc) without requiring apps be relinked with newer versions of the SDK. THe only reason to update to newer versions of the SDK (like 6.1) would be to use the new stuff introduced in that version. – Streeter Jul 10 '13 at 19:13
  • I really doubt that's what they did :P Re-compile the old SDK? If what they want is backwards compatibility to not break old apps that doesn't make sense. – Javier Soto Jul 10 '13 at 20:32