Xcode 5 Developing for OS X 10.6 - cocoa

I have 10.9/Xcode 5 and I'm trying to write a Cocoa app for Snow Leopard. I deactivated auto layout and set the deployment target to 10.6, but the archived application won't launch on 10.6 because it can't load the nib (console output). From what I've read, I need to use garbage collection instead of ARC. If this is true, how to I modify my project to build and run for 10.6? Thanks for your advice.

First, make sure the XIB itself is configured to build for 10.6. In the right-hand pane of Interface Builder, you should see this:
If you're targeting 64-bit 10.6, then you can use ARCLite, which is just fine and I strongly recommend it. The only thing you really give up is auto-zeroing weak references. You only have to give up ARC if you go 32-bit. I recommend sicking to 64-bit if you can possibly help it. You give up a lot if you target 32-bit. To use ARCLite, you don't have to change anything. It's automatically selected when you compile an ARC program for 10.6.
As a note: yes, what you're doing is totally possible. I still target 10.5 with a 10.9/Xcode5 setup.

Related

Compiling App for older OS X versions

I recently submitted (my first) app to the AppStore. It works on OS X 10.8 and uses some of the 10.8 features like ShareKit. I wanted to support OS X 10.7 also, to make it available for 10.7 users. Of course, this would mean that the 10.7 version will not have the ShareKit features. But I'm not sure what compile settings to use to make it available for both, so that 10.8 users will be able to make use of the features and 10.7 users will not see them.
I tried changing the Base SDK to 10.7, but it won't compile on that.
I tried changing the deployment target to 10.7 keeping the Base SDK 10.8. It compiled, but I'm not sure if that is the right thing to do. Don't have a 10.7 machine to test it, either.
If case 2 is correct, how do I check the in the code and make the menu items disabled?
number 2 is the correct thing to do, but being able change sdk to 10.7 is very nice, because in general if it won't compile because a class or method is missing it won't run.
you will need to re-write code to dynamically detect if things are available for use...
Class Some108Class = NSClassFromString(#"The10_8Class"); //will be Nil in 10.7
or
[var respondsToSelector:#selector(someMethod)]; // returns no if someMethod isn't available
[SomeClass instancesRespondToSelector:#selector(someMethod)];//same

How do you debug an app for an older version of Mac OS X?

I am developing an app using Xcode 4.6 on an OS X 10.8 machine. The app deployment target is set to 10.6, which is what we need to support. But when I archive the app (compile, link and embed resources+frameworks) and deploy (aka copy) it to the 10.6 test machine, it crashes with a generic Segmentation fault. It works fine on 10.7.
I can't compile the project in Xcode on the older Mac because the app is built using the newer compiler (it uses ARC, implicit property synthesis, the new objective-c literal syntax, etc.). It also wouldn't type check because the base SDK is 10.8 and it references some 10.8 tokens which the compiler on the 10.6 machine doesn't know about.
Any suggestions on how to go about debugging the app?
I'm not affiliated with this company/software in any way, but Deploymate is a paid app which can scan your app for SDK usage and tell you when you are calling selectors and APIs that are unavailable on older OS versions. This can help you track down exceptions and crashes relating to API usage.
You are very likely using one or more 10.7+ APIs that crash on 10.6. With a 10.8 target SDK you allow all the calls to function that are available in that SDK. However apps are bound late so this doesn't crash when you do not actually call those functions. You need an explicit check similar to this (here for the full screen feature):
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6
if (runningOnLionOrLater) {
[mainWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
[toggleFullscreenItem setHidden: NO];
}
#endif
One way to determine the current version is:
int macVersion;
if (Gestalt(gestaltSystemVersion, &macVersion) == noErr) {
runningOnLionOrLater = macVersion > MAC_OS_X_VERSION_10_6;
}
For debugging the problematic calls simply set the base SDK to 10.6 and XCode should mark those functions that are not available there.
While there is no real good solution to this (I've seen simply different behaviors on different macOS versions) and no way to simply simulate an older macOS version, if you have a machine to spare:
It is possible to use an external HD, partition it and install different macOS versions. They all can be bootable and it's a matter (pain) of restarting the machine for every OS version.

NSWindowController window?

I have a menu-bar based application, which displays a window, when the icon is clicked.
It all works fine on Mac OS X Lion, but for some reason, an error occurs on Snow Leopard an sooner versions of Mac OS X. Anytime [TheWindowController window] is called the method stops, but the app keeps running. Because of this, I don't think that the window is just nil, it's corrupt, in some way.
I have no Idea why this happens, and like I said, it only happens in Mac OS X Snow Leopard.
Btw. I use ARC, if that matters at all.
You're loading a NIB that uses a 10.7-specific feature, Cocoa Autolayout, on 10.6, which doesn't understand it. If you wish to support running on 10.6, you need to avoid using such features. You should be able to set the deployment target on the NIB, which will then cause warnings to show up for features which aren't supported by that deployment target.
Also, if you haven't already done so, you need to do something similar for your target's build settings. Set the deployment target. Unfortunately, that won't necessarily cause warnings for code which uses features that were introduced in 10.7. You can set up an alternative build configuration which builds against the 10.6 SDK and compile against that to learn where you're using post-10.6 features. See Apple's SDK Compatibility Guide for more info.

How to avoid XCode framework weak-linking problems?

I'm building an application that takes advantage of Mac OS X 10.6-only technologies, but without giving up backwards compatibility to 10.5 Leopard.
The way I do this is by setting the 10.6 SDK as the base SDK, weak-linking all frameworks and setting the deployment target to 10.5 as described in:
http://developer.apple.com/mac/library/DOCUMENTATION/MacOSX/Conceptual/BPFrameworks/Concepts/WeakLinking.html
This works fine; before making a call that is Snow Leopard-only I need to check that the selector or indeed the class actually exist. Or I can just check the OS version before making the call.
The problem is that this is incredibly fragile. If I make a single call that is 10.6 only I blow Leopard-compatibility. So using even the normal code code completion feature can be dangerous.
My question: is there any way of checking which calls are not defined on 10.5 before doing a release build? Some kind of static analysis, or even just a trick (a target set the other SDK?) would do.
I obviously should test on a Leopard machine before releasing anything, but even so I can't possibly go through all paths of the program before every release.
Any advice would be appreciated.
Best regards,
Frank
You could change the target SDK to 10.5. The compiler will then output warning: definition for '-snowLeopardOnlyMethod:' not found messages.

How do you enforce the minimum OS requirements in a Cocoa app?

My app needs to run on 10.4 or later. If I launch it on 10.3 it just fails to launch or crashes.
How do you tactfully enforce minimum system requirements? Can you customize the message it shows?
Add a key to your applications Info.plist, specifying LSMinimumSystemVersion as 10.4.X for whatever X you need as a minor version. For more, see Apple's documentation.
I have not used either of these techniques/advice, just passing along the information I have gathered.
You might try something like the SystemVersionCheck “shim” executable to provide a working OS version check for versions that do not honor LSMinimumSystemVersion (e.g. 10.3).
The pre-compiled executable is PPC-only. You might need to rebuild it to support PPC and Intel machines so that it works with 10.3, but also so that 10.6 users are not prompted to needlessly install Rosetta. I found a blog entry that has a hint on how to setup the PPC build to target 10.3 and the Intel build to target 10.4u (it was written about 10.5 and Xcode 3.0 though—do the latest versions of Xcode even include the 10.3 SDK?).
If you experience a crash after adding the LSMinimumSystemVersion key to your app's plist manually, then this is due to the Finder not recognizing the changed state of the app properly. Either restart the Finder (e.g. log out) or duplicate the app in the Finder. The copy will then behave correctly.

Resources