2

Okay I know there's a lot of posts on this, but I'm still having trouble. Here's the pseudo code for what I'm trying to do:

if(device is running iOS 5 or up)

    @interface RootViewController : UIViewController <UIPageViewControllerDelegate, UIGestureRecognizerDelegate>

    @property (strong, nonatomic) UIPageViewController *pageViewController;

else

    @interface RootViewController : UIViewController <LeavesViewDelegate, UIGestureRecognizerDelegate>

    @property (strong, nonatomic) LeavesViewController *leavesViewController;

endif

Am I right in thinking I need to use pre-processor macro checks since it's in the header file? It's a book app that should use UIPageViewController if it's iOS 5 or up (and therefore has UIPageViewController), otherwise it falls back on Leaves (https://github.com/brow/leaves). I have all the code set up. Just need to know how to tell the compiler which to use. I don't think using any runtime checks would work since I only need the protocol methods for either UIPageViewController or Leaves compiled, not both. And I'd rather not use completely separate source files. I've tried using these checks:

#ifdef kCFCoreFoundationVersionNumber_xxx

#ifdef __IPHONE_xxx

#if __IPHONE_OS_VERSION_MAX_ALLOWED <__IPHONE_xxx

(with various xxx's)

What am I missing here?

EDIT:

I also noticed this in the default .pch:

#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

which makes me wonder why that same test didn't work in my .h file?

Marty
  • 5,926
  • 9
  • 53
  • 91
  • 1
    Most of the time, iOS binaries are not compiled separately for differing versions of the OS; only one binary is compiled with a "base SDK" setting of version X and a "deployment target" (backwards-compatibility) setting of version Y, where X >= Y. As such, you can't do this with preprocessor macros unless you intend on deploying separate apps on the store but building from the same codebase. – inspector-g Apr 20 '12 at 06:33
  • so what would be the standard way to deal with this? do i need to change it to just use only runtime checks? – Marty Apr 20 '12 at 06:34
  • would i have two targets, and then use the preprocessor checks so that it compiles the two targets differently? – Marty Apr 20 '12 at 06:38
  • Yes, you can only do this with runtime checks. However, the complexity of the tasks involved may exceed any sane man's willingness to implement them, and you'll likely find it far easier to simply use Leaves until you feel its acceptable to your users to drop it entirely. – inspector-g Apr 20 '12 at 06:51
  • If you still want to go down that path, you may need to utilize several methods from i.e. [this thread](http://stackoverflow.com/questions/211616/hidden-features-of-objective-c) on class posing, ISA switching, etc. I have had to do runtime feature checks in several apps, but never runtime interface/delegate checks and changes so you're on your own from here. Sorry I can't be of more help. – inspector-g Apr 20 '12 at 06:52
  • plenty helpful. i'm going to try just having the header files include everything required and then use runtime checks. – Marty Apr 20 '12 at 07:00

2 Answers2

0

you can't do this, as preprocessor macros are processed at compile-time. How should the compiler know, which iOS you're targeting, since you're compiling on your Mac and not everybody on his iPhone?

You cannot easily switch code at runtime. There are possibilities, but I don't think it is meant like you want it to be.

You can check at runtime if methods are available from specific SDKs. This is much simpler and straightforward. However you cannot achieve your goal with that.

I suggest: Create a superclass, where you do not have the specific delegate protocols included. There you write all your code, you want to share.

Then create 2 subclasses from upper superclass. In each of the classes put in your specific code.

AND THATS IT. This is the way it should be.

Fab1n
  • 2,103
  • 18
  • 32
0

As I mentioned in the comments, you can't do this at compile time.

But here's an idea for you: It seems that the method names of UIPageViewControllerDelegate and LeavesViewDelegate do not intersect, so you could add the following to your header file:

-(void) leavesView:(LeavesView*)leavesView willTurnToPageAtIndex:(NSUInteger)pageIndex;
-(void) leavesView:(LeavesView*)leavesView didTurnToPageAtIndex:(NSUInteger)pageIndex;
-(void) pageViewController:(UIPageViewController*)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray*)previousViewControllers transitionCompleted:(BOOL)completed;
-(UIPageViewControllerSpineLocation) pageViewController:(UIPageViewController*)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation;

and not explicitly adopt the delegate protocols in the header file (leave out the delegates inside the < >).

Whatever classes you're using for these two could be instantiated in your *.m file in a condition along the lines:

// check for existence of class to determine which controller to instantiate
if(NSClassFromString(@"UIPageViewController"))
{
    // do something and set UIPageViewController delegate to "self"
}
else
{
    // do something else and set LeavesViewController delegate to "self"
}

Lastly, to get this to compile, you will probably need to forward declare all LeavesViewController- and UIPageViewController-related classes where you use them, and possibly utilize weak linking for some frameworks.

I haven't yet used Apple's UIPageViewController classes and protocols, so I can't provide much more insight than this. Be sure to let us know if you get something hammered out :)

inspector-g
  • 4,146
  • 2
  • 24
  • 33