-2

Is there any way to setup uncached and nearly, if not completely, predetermined values for my application based on the iOS version without having to manually call initialization code at runtime?

I am not looking for a solution that requires me to either constantly check against the OS while the application is running or have to initialize a number of global variables at run time by making a call through the AppDelegate.

RileyE
  • 10,874
  • 13
  • 63
  • 106
  • 3
    The information about what system is running code doesn't exist at compile time. How could it? Have you seen [Run time vs compile time iPhone version check](http://stackoverflow.com/q/6617832)? – jscs Jun 11 '13 at 20:34
  • @JoshCaswell I'm sorry for the confusion. I wasn't expecting an actual compile time check, but some alternative. I just don't want to have to constantly check against the iOS version when I need the enum value. – RileyE Jun 11 '13 at 20:35
  • Your question seems to be asking for preprocessor macros times -- you mention them several times. If you're looking for an _alternative_ to them, you should make that more clear. – jscs Jun 11 '13 at 20:38
  • @JoshCaswell I don't know of any way to depict what I want without showing it in this manner. That is why I'm asking what to do. If I knew the alternative, I wouldn't need to ask. :) – RileyE Jun 11 '13 at 20:38
  • @JoshCaswell I've edited to state that I'm looking for an alternative. – RileyE Jun 11 '13 at 20:39
  • http://stackoverflow.com/questions/3339722/check-iphone-ios-version – Daij-Djan Jun 11 '13 at 20:39
  • @Daij-Djan That won't help as that will require me to either check the OS constantly or initialize global variables through the AppDelegate, just what I was asking to avoid in my question. – RileyE Jun 11 '13 at 20:40
  • 2
    Sure, I understand that, but your question sort of reads right now like "My doctor says I need more potassium in my diet, but I hate bananas, so what kind of banana should I eat?" when you're actually loooking for an option other than a banana. – jscs Jun 11 '13 at 20:42
  • writing an example of how to do it – Daij-Djan Jun 11 '13 at 20:43
  • that sets up a define that at runtime results in a version call. you could even cache it if you want – Daij-Djan Jun 11 '13 at 20:45
  • @JoshCaswell I think it's a very valid question as I am not asking what kind of potassium rich foods can I eat, as there are a vast number of those. And I made an error in my edit. That has been corrected, now. – RileyE Jun 11 '13 at 20:45
  • 2
    I think it's a valid question, too; I'm just trying explain that what you seem to be looking for based on your comments doesn't match the question. Maybe I'm not doing such a good job explaining that... – jscs Jun 11 '13 at 20:47
  • Please post your solution as an answer rather than an edit to the question; [self-answering](http://meta.stackexchange.com/questions/17463/can-i-answer-my-own-questions-even-if-i-knew-the-answer-before-asking) is both allowed and encouraged. You can even mark it as accepted, although I believe there's a wait period of a few hours. – jscs Jun 11 '13 at 21:32
  • @JoshCaswell Okay. I've removed it. Thank you! – RileyE Jun 11 '13 at 21:38
  • @JoshCaswell I've also edited my question. Does it make more sense for potential future viewers? – RileyE Jun 11 '13 at 21:49
  • It looks good to me, although I think it would also be fine without the code snippet. – jscs Jun 11 '13 at 23:40

2 Answers2

2

You can't check the system version at compile time. That information simply doesn't exist.

The best you can do, since you want to avoid re-checking multiple times throughout a run of your app, is check very early in the process lifetime and store that information. This may be an appropriate task for your application delegate. When you get application:didFinishLaunchingWithOptions:, do the usual runtime check and make the result available to whatever other controllers need it. Or have each controller that cares do the check when it's created.

You could also create a function with the constructor attribute, which will be run extremely early -- before main(), in fact, although after framework classes have been loaded. This can simply initialize a global variable with the system version that you can then access wherever you like.

jscs
  • 63,694
  • 13
  • 151
  • 195
  • Do you mean adding this: `__attribute__((constructor))` to the line before the method declaration? Will that cause the function to be run before the application can load anything, so that I don't have to check if the value has been initialized, but just trust that it has been initialized, since it has been run before any calls could be made to it? – RileyE Jun 11 '13 at 21:07
  • The attribute won't work on a method; it has to be a function. And yes, as I said, the function will be run before `main()`, thus before `UIApplicationMain()`, and before any of the rest of your code. It may even be _too_ early; I'm not 100% sure that `UIDevice` will be initialized yet. You'll have to try it. – jscs Jun 11 '13 at 21:10
  • Ah! Right. That wouldn't make sense to use a method, as I don't need an instance of anything. Then this will definitely work out well for me. I'm going to edit my question to reflect what I've taken from all of this. – RileyE Jun 11 '13 at 21:12
  • @JoshCaswell As I've proven in my [iOS app in pure C](http://stackoverflow.com/questions/10289890/how-to-write-ios-app-purely-in-c/10290255#10290255), you can use objc classes in a `__attribute__((constructor))` function. – Richard J. Ross III Jun 11 '13 at 21:18
  • @Daij-Djan It will work (I create a UIView subclass using a constructor function), and I have shown it to be reliable, on both the simulator and the device: http://stackoverflow.com/questions/10289890/how-to-write-ios-app-purely-in-c/10290255#10290255. – Richard J. Ross III Jun 11 '13 at 21:18
  • @RichardJ.RossIII: Right, thanks, the docs for `+[NSObject load]` actually make this clear. – jscs Jun 11 '13 at 21:27
  • @RileyE: Actually, it seems `UIDevice` will be perfectly usable at that point; I've updated my post. – jscs Jun 11 '13 at 21:28
  • @RichardJ.RossIII If I need to use the objc functions, then how would I go about calling the selector `compare:options:`? Would it be like this: `iOS6OrGreater = ((int)objc_msgSend(objc_msgSend(objc_msgSend(objc_getClass("Device"), sel_getUid("currentDevice")), sel_getUid("systemVersion")), sel_getUid("compare:options:"), "6.0", 64) != NSOrderedDescending);` – RileyE Jun 11 '13 at 21:33
  • @JoshCaswell Oh. So that last comment was a waste of time on my part, huh. – RileyE Jun 11 '13 at 21:33
  • There's absolutely no need to use those functions, @RileyE. The compiler can handle ObjC code inside an otherwise plain-C function perfectly well. The issue I was worried about was not use of ObjC, but use of _framework_ objects which I wasn't sure had been loaded into memory yet. – jscs Jun 11 '13 at 21:34
  • @JoshCaswell Wouldn't the `UIDevice` be considered to be a part of those *framework* objects? – RileyE Jun 11 '13 at 21:39
  • @RileyE: Exactly; that's what I was concerned about, but the framework _is_ loaded before your constructor is called. – jscs Jun 11 '13 at 21:41
  • Okay. I misunderstood. Sorry. Thank you VERY much! This has been a great source of learning for me. Especially seeing what @RichardJ.RossIII wrote up in his pure C iOS application. – RileyE Jun 11 '13 at 21:44
1

Using the advice from @JoshCaswell, I've attempted this the following way:

static BOOL iOS6OrGreater;

__attribute__((constructor))
static void iOS6OrGreaterInitialization(){iOS6OrGreater = [[[UIDevice currentDevice] systemVersion] compare:@"6.0" options:NSNumericSearch] != NSOrderedDescending;}

static int MY_DEFINED_ENUM_NAME(){return (iOS6OrGreater) ? IOS6_OR_GREATER_ENUM : IOS5_OR_LESSER_ENUM;}

However I am getting the 'UITextAlignmentCenter' is deprecated: first deprecated in iOS 6.0 warning.

RileyE
  • 10,874
  • 13
  • 63
  • 106
  • 1
    Just suppress the warnings: http://stackoverflow.com/questions/1902021/suppressing-is-deprecated-when-using-respondstoselector – Richard J. Ross III Jun 11 '13 at 21:57
  • @RichardJ.RossIII Thank you! I'm also getting a `Value Conversion Issue`, but I don't know what the warning flag name is. How would I figure that out to suppress it, since I don't want to suppress all warnings. – RileyE Jun 11 '13 at 22:09
  • You don't suppress it, you should be casting the values to `int` – Richard J. Ross III Jun 11 '13 at 22:12
  • @RichardJ.RossIII I was, but when I was grabbing the values, I forgot to state that it was a function with the parentheses. It was a stupid mistake. – RileyE Jun 11 '13 at 22:14