Writing iOS7 code that compiles against iOS 6 Base

2019-02-13 13:11发布

问题:

We have an iOS app on-sale now, and we're developing the iOS 7 version on XCode 5 DP using the same code base.

We really need to release an update right now for existing iOS 5/6 customers but, of course, when we re-load the project into XCode 4, it complains about non-existing properties since the Base SDK then becomes iOS6, not 7:

// Only run this bit on iOS 7
if ([self respondsToSelector:@selector(setFooForExtendedLayout:)])
{
    self.fooForExtendedLayout = UIFooEdgeLeft | UIFooEdgeRight;
}

float bottomOffset = 0;
// Only run this bit on iOS 7, else leave bottomOffset as 0
if ([self.hostController respondsToSelector:@selector(bottomLayoutFoo)])
    bottomOffset = self.hostController.bottomLayoutFoo.length;

(obfuscated to avoid breaking NDA)

XCode Errors:

Property 'fooForExtendedLayout' not found on object of type 'UIViewController *'

Use of undeclared identifier 'UIFooEdgeLeft'

Use of undeclared identifier 'UIFooEdgeRight'

Property 'bottomLayoutFoo' not found on object of type 'UIViewController *'

It would be a pain to comment out this new code. What is the correct way to re-write it to be compatible with both the old and new Base SDKs, and does submitting it now (via XCode 4 and built against iOS 6 SDK) risk any sort of App Store rejection?

回答1:

I would advise to wait until iOS 7 is ready to submit your update.
However, they are ways to fix the issue.

Property 'fooForExtendedLayout' not found on object of type 'UIViewController *'

As properties are just a syntactic sugar, the easy way to fix this kind of error is to use a selector to call the method (setter):

[ self performSelector: NSSelectorFromString( "setFooForExtendedLayout:" ) withObject: ( id )xxx ];

@selector() can't be used since you're asking for an iOS 7 selector with an iOS 6 SDK.
Hence the use of NSSelectorFromString.
The withObject argument is made for objects, as it names implies. But as objects are pointers, and as your method takes an enum value, you can actually pass it without problem, using a cast.

Use of undeclared identifier 'UIFooEdgeLeft'
Use of undeclared identifier 'UIFooEdgeRight'

Now about your enum values, there's no such trick.
The only way is to declare them, with the same values as in the iOS 7 SDK, and pray that it won't change until the official release.

So now it's up to you... Personally, I would wait.



回答2:

Here is the recommended way to have code that compiles on both iOS 6 and 7 SDK:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
    if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)])
        self.edgesForExtendedLayout = UIRectEdgeLeft | UIRectEdgeRight;
#endif


回答3:

You could use:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    self.edgesForExtendedLayout = UIRectEdgeNone;
}
#endif


回答4:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
{
    self.edgesForExtendedLayout = UIRectEdgeNone;
}
#endif


回答5:

Edit: this answer (and also the questions) is not relevant anymore since now Xcode 5 is released! Please consider this when down-voting ;)

The rationale for using a SCM tool to get two different code branches is due to subtle issues that can arise when switching Xcode Developer Preview versions and a Xcode Release versions with an identical Xcode project and same code and resource base. The project file and storyboard or xib may be changed under the hood, and possibly may get corrupt. It's not because there would be no way to find a solution in code! Nonetheless, I wouldn't recommend to work with different Xcode versions on the identical Xcode project. This may cause you headache!


The correct way is to use a source code management tool, like git. You should have an "iOS 6" branch, where you maintain release versions, and you should have one or more development branches where you use prerelease versions of Xcode and iOS.



标签: xcode ios6 sdk