1

I've been learning more about Cocoa, Objective-C, and Xcode by contributing to an open-source project (IPMenulet); the project originally supported OS X 10.5.

In my haste, it seems that I have added features using SDK elements (NSJSONSerialization and the @autoreleasepool compiler directive) that aren't supported by the older SDK. Now, I'm trying to determine what if anything I can do to restore support for 10.5

Options:

  • NSJSONSerialization - I suppose that I could switch to JSONKit
  • @autoreleasepool {} - ?
  • @properties - add @synthesize and IVARs

Questions:

  • is there a way (compiler directives?) to use newer SDK elements if the OS supports it, switching to the older element if necessary? if so, is it better to refactor the functionality in version-specific methods (e.g. getJSONlegacy, getJSON)?
  • would it be better to mark the original project as a separate branch (to allow it to be enhanced)?
craig
  • 25,664
  • 27
  • 119
  • 205
  • 1
    The point of the newer features is to leave older OSes behind. You need to go lowest-common-denominator when backporting. Rollback everything and start again. You don't necessarily need dependencies to replace everything, either. JSON parsers are trivial to write, you should know MRC already, and property synthesis is a feature of clang, not the OS. – CodaFi Apr 22 '14 at 13:16

2 Answers2

1

Different features involve different OS components, which defines how a feature can be used in multiple OS X versions. Here is my rough classification:

  • functionality is completely provided by some framework. For example, NSJSONSerialization is available in Mac OS X 10.7+. You can use the same solution for all OS versions or check at runtime if some functionality is available. For example,

    if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)])
        [view setAcceptsTouchEvents:YES];
    

    More details regarding multiple SDKs support can be found in SDK Compatibility Guide. Using SDK-Based Development.

  • functionality is completely provided by compiler. For example, @autoreleasepool, literals.

  • functionality is provided by compiler and runtime. For example, default @property synthesis. See Objective-C Feature Availability Index for more details.

  • functionality which depends on SDK against which an application is linked. It is more about behavior changes, such a mechanism is described in Backward Compatibility section in AppKit Release Notes.

And now back to your question. There is a mechanism to check in runtime if a feature is available, pretty often respondsToSelector: can do the job. I recommend to expose a single method which works on all OS versions. And only inside this method differences between OS versions are present. For example,

- (NSString *)base64EncodingForData:(NSData *)data {
    NSParameterAssert(data);
    if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
        return [data base64EncodedStringWithOptions:NSDataBase64Encoding76CharacterLineLength];
    }
    else {
        // Manual encoding using <Security/SecEncodeTransform.h> and kSecBase64Encoding.
    }
}

You can create some 1.1 maintenance branch, perform all work in master, and merge to maintenance branch only bugfixes. So from maintenance branch you'll release 1.1.1 and from master 1.2. It's a viable approach. But you cannot support Mac OS X 10.5 indefinitely, so you need to decide in which IPMenulet version you'll drop 10.5 support.

Volodymyr Sapsai
  • 413
  • 5
  • 13
1

To the extent that it helps at all, the classic version of:

@autoreleasepool { ... code ... }

Was:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

... code ...

[pool drain];

drain is preferred to the normal release because it then all works properly with (also now deprecated) OS X garbage collection. But it counts as a release so there's no memory leak and you shouldn't also release.

Tommy
  • 99,986
  • 12
  • 185
  • 204
  • Is the code (`... code ...`) between the `init` and `drain` marked as `autorelease` without having to do any additional work? – craig Apr 24 '14 at 00:40
  • Not without ARC; you need explicitly to `autorelease`. The objects will go into `pool` and then be completely released when it is drained. So all you're doing is attempting to avoid memory footprint bottlenecks — just like with `@autorelease`. – Tommy Apr 24 '14 at 02:27