iOS version skew

Dear Lazyweb,

I have code that does:

NSXMLParser *xmlDoc = [[NSXMLParser alloc] initWithContentsOfURL:furl];
[xmlDoc parse];

Running on iOS 6, this works. Running on iOS 5, the parse call destroys the stack with "dyld: Symbol not found: _objc_setProperty_nonatomic".

What does this mean and how do I fix it?

My settings are "Base SDK: Latest iOS (6.1)", "iOS Deployment Target: iOS 4.3". Some googling suggested changing the latter to 6.1, but that changes nothing. What is the "deployment target", anyway? If I set it to 6.1, doesn't that mean the app will not run on anything earlier than 6.1?

As far as I know, this code should work all the way back to iOS 3.0, but Apple won't even let you target that any more. I'd rather not ship binaries that artificially require later versions of the OS than is strictly necessary.

Build environment is Xcode 4.6.2 on OSX 10.8.3.

Tags: , , , ,

14 Responses:

  1. Brad J says:

    Some subproject or similar is set to a deployment target of 6.0 or later, or does not have a deployment target set (which, stupidly, means it defaults to the latest), or has a target set to a version earlier than that version of XCode can support (same default, even more stupid). That method was added in iOS 6. Basically, make sure everything is explicitly set to 4.3 or similar.

    • jwz says:

      It all looks the same to me. I have one static library, and one iOS app. How do I tell what it thinks is out of sync?

      This is a maze of twisty passages because all of this also builds for MacOS. And GC is required for screen savers on 10.6 but prohibited on all other releases from 10.4 through 10.8. And WTF is this "auto-reference counting" shit? I assume that I need to turn that off everywhere.

      The Project says:
      - Base SDK: Latest OS X (10.8)
      - Deployment target:
      -- Any iOS SDK: Compiler Default

      The library says:
      - Base SDK:
      -- Debug: Latest OS X (10.8)
      --- armv7, armv6: Latest iOS (iOS 6.1)

      The iOS app says:
      - Base SDK: Latest iOS (6.1)
      - Deployment Target: iOS 4.3 (or 6.1, same failure)

      • Peter Bierman says:

        IIRC, you can't build a library that works for GC and not-GC. So you might need to build two versions of the static library.

        (Why a static lib at all? Why not just build the sources directly for each target?)

        "Auto-reference counting" is Apple finally realizing that GC can never not suck, so they taught the compiler all of the conventions for manual retain/release, and it inserts that code for you. It gets it right far more often than most developers, but not quite as often as really experienced ones, and the consequences are the same ones we already have tools to help find: leaks or over-releases. I wish it literally added (or showed) the code though; I hate invisible side-effects.

        • jwz says:

          The way this used to work was, set the GC setting to "allowed" (instead of "prohibited" or "required") and that made it work. On OSX, screen savers are bundles that are dynamically loaded into the running ScreenSaverEngine app, and in 10.6, that app had GC turned on, so all loaded bundles also need to support GC. That change made older savers start working. Then in 10.7 they turned GC off again, so savers bundles that were built with GC required also stopped working. And the whack-a-mole continues with "ARC" I guess.

          Since the current Xcode UI displays the GC preference as GC_ENABLE_OBJC_GC instead of English words, does that mean that the current Xcode can't build GC-capable bundles at all, and it's now impossible, on a 10.8 system, to build screen savers that will run on a 10.6 system?

          This wouldn't surprise me at all, since Apple pulls this kind of shit all the time, but I'm gonna get whiny mail about it.

          • hattifattener says:

            ARC is substantially less terrible than GC was, because it's not a whole-process all-or-nothing thing. It's OK for some files to be compiled with it and some without. There are still a bunch of bad ideas in there, but they're easier to work around than the GC bugs were...

            Anyway. Can you just find the object file that references that symbol with some kind of 'find . -name "*.[oa]" -print0 | xargs -0 nm -o | fgrep objc_setProperty_nonatomic' in your intermediates/products directories?

        • jwz says:

          And the reason it's a library is because it's, you know, a library. A collection of utility functions, varying subsets of which are used by the other 200+ targets in the project.

          • Peter Bierman says:

            Yeah, but that library never leaves your project, right?

            GC & ARC are kind of like ABIs*, so now each of your targets have 3 possible flavors, and each flavor is going to need to link against the matching flavor of the library. That sounds like a bigger build configuration headache than adding a folder of sources to each target, but maybe there's some automagic way.

            [*] in the sense that calling code needs to know which convention was used by the library code.

  2. Peter Bierman says:

    The BaseSDK is the headers and libraries you are building against. Anything in it that differs from the OS the code can run on is your responsibility to deal with gracefully.

    IOW, if you don't intend to use any features newer than iOS 4, set your BaseSDK to iOS 4.

    Apple usually recommends the opposite approach, because most of the testing goes into making sure the latest tools work correctly with the latest libraries.

    If they would have let us run 10.5 in a VM, this wouldn't all be quite as annoying. You could run the tools that shipped with the SDK you want. But backwards compatibility is a necessary evil, not a beloved feature, so it's ever onward to our glorious future!

    • jwz says:

      I only have the 10.7 and 10.8 SDKs. The others vaporized with some Xcode upgrade or another. Are those downloadable?

      • Ronan Waide says:

        I've successfully pulled the 10.6 SDK tree out of a backup, dropped it in Xcode's tree, and built against it. Alas the code in question has a compiler-related bug so I can't state with certainty that the resulting builds actually work.

      • Peter Bierman says:

        I think you can find the older SDKs and put them in the right place, but I would not be surprised by weirdness. The tools (compiler,etc) have changed lots, and if Apple isn't providing those SDKs for the current tools there's probably a reason.

        I'd set up a machine with the last OS & Xcode versions that supported the earliest iOS you want to target. Maybe cram the whole thing onto a 16GB SD card. Then build the project on that.

        Anything else and you're swimming upstream.

      • Dave says:

        Downloads for Apple Developers - https://connect.apple.com/, or maybe https://developer.apple.com/downloads/index.action. There's a bunch of older Apple development tools & libraries in here, including old versions of Xcode, which in turn contain older versions of the OS X and iOS SDKs.

        Xcode 3.2.6 may be of particular interest: it's the last of the 3.x series, and according to Wikipedia: "Xcode 4.0 drops support for many older systems, including all PowerPC development as well as SDKs for Mac OS X 10.4 and 10.5, and all iOS SDKs older than 4.3."

  3. Anonymous Coward says:

    Given that it's this week, get someone to loan and/or forge you a WWDC badge, then wander over to the Moscone Center to yell at Apple engineers until they explain what's going on?