Compiler errors after upgrading to XCode 4 - iphone

I've upgraded xcode and ios sdk to the latest version (xcode 4.0 / ios sdk 4.3) and now I'm getting compiler errors on a project that was building before.
This is the code:
- (void)layoutSubviews
{
int w = 320;
int h = 480;
float ver = [[[UIDevice currentDevice] systemVersion] floatValue];
// You can't detect screen resolutions in pre 3.2 devices, but they are all 320x480
if (ver >= 3.2f){
UIScreen* mainscr = [UIScreen mainScreen];
w = mainscr.currentMode.size.width;
h = mainscr.currentMode.size.height;
if( ver >= 4.0f ) {
float scaleFactor = mainscr.scale;
// this will scale the OpenGLView for retina screens
self.contentScaleFactor = scaleFactor;
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.contentsScale=scaleFactor; //new line
}
}
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer *)self.layer];
setOpenGLSize(w,h);
[self drawView:nil];
}
And these are the errors:
error: property 'scale' not found on object of type 'UIScreen *' [2]
error: property 'contentScaleFactor' not found on object of type 'EAGLView *' [2]
error: property 'contentsScale' not found on object of type 'CAEAGLLayer *' [2]
I have Base SDK setted to iOS 4.3 and deployment target to iOS 3.0
If i set deplyment target to 4.3, the error dissapear, but I want the app to run on 3.0 and above.
What's wrong with the code or the project?

"I have Base SDK setted to iOS 4.3 and deployment target to iOS 3.0"
So it is warning you that the properties scale, contentScaleFactor and contentsScale were introduced in 4.0 and you can't use them in 3.x.
If you really want to deploy to 3.x (and everything I've seen says it is of questionable worth to make your app support it, especially since the unification of iOS post-iPad2) then you have to work around those properties not being there.

Related

Identify iphone's version

I'm developing an app which can only be installed in iPhone 4 and later versions.I also go through UIRequiredDeviceCapabilities and Device Compatibility Matrix.I need more solution.
Well, first of all you can receive the model as a string using the UIDevice class:
[[UIDevice currentDevice] model]
This will return something like "iPod touch" or "iPhone".
You can get the exact model platform using the following code:
(you have to #include <sys/types.h> and <sys/sysctl.h>)
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *machine = malloc(size);
sysctlbyname("hw.machine", machine, &size, NULL, 0);
NSString *platform = #(machine); // Old syntax: [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]
free(machine);
Now platform is a string containing the generation of the device, e.g.:
iPhone1,1 for the iPhone 2G (the first iPhone)
iPhone1,2 for the iPhone 3G
iPhone2,1 for the iPhone 3GS
iPhone3,1 or iPhone3,2 for the iPhone 4
iPhone4,1 for the iPhone 4S
iPhone5,1 or iPhone5,2 for the iPhone 5
Note that the number in front of the comma of the iPhone 4 platform is actually 3, not 4.
Using this string you can isolate this number and check if it is greater than or equal to 3:
if ([[[UIDevice currentDevice] model] isEqualToString:#"iPhone"]) {
if ([[[platform componentsSeparatedByString:#","][0] substringFromIndex:6] intValue] >= 3) {
// Device is iPhone 4 or newer
} else {
// Device is older than iPhone 4
}
}
However: You can actually check the screen's scale, since the iPhone 4 is the first iPhone with a retina display:
[[UIScreen mainScreen] scale] // Returns 2.0f on the iPhone 4 and newer and 1.0f on older devices

UIRefreshControl use in iOS6 but not in iOS5

I want to add a UIRefreshControl for iOS6 users and a button for iOS5 users. I only want to have one package I deliver to the app store (obviously) so how can I do this?
I can sense the OS version
float ver = [[[UIDevice currentDevice] systemVersion] floatValue];
if (ver >= 6.0) {
// Programmatically add UIRefreshControl.
}
But if I want to support iOS5, the compiler won't let me use the UIRefreshControl?
If the compiler don't let you use it, then let you fool him. You can (and should) also switch from OS version detection to feature detection. All in all:
if (NSClassFromString(#"UIRefreshControl") != Nil) {
id control = [[NSClassFromString(#"UIRefreshControl") alloc] init];
}

I need to maintain both sdk (3.0 and 4.0). But in 3.0 sdk I am getting error

I need to maintain both sdk (3.0 and 4.0). But in 3.0 sdk I am getting error.
CGFloat maxScale;
if ( [[UIScreen mainScreen] respondsToSelector: #selector (scale)] == YES )
{
maxScale = 1.0 / [[UIScreen mainScreen] scale];
}
else
{
maxScale = 1.0;
}
warning: 'UIScreen' may not respond to '-scale'
error: invalid operands to binary / (have 'double' and 'id')
How do I solve this problem?
If you want your code to be different when you build with different SDK versions then you need to use preprocessor:
#if __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED
maxScale = 1.0 / [[UIScreen mainScreen] scale];
#else
maxScale = 1.0;
#endif
But normally you do not need that, build your project with the latest SDK you have and set appropriate value to the "iOS Deployment Target" property of your target. Then your application will run on sdk versions you specified and code you have will make run-time check if -scale method is present.

Check iOS version at runtime?

This is sort of a follow on from my last question. I am using beginAnimations:context: to setup an animation block to animate some UITextLabels. However I noticed in the docs that is says: "Use of this method is discouraged in iOS 4.0 and later. You should use the block-based animation methods instead."
My question is I would love to use animateWithDuration:animations: (available in iOS 4.0 and later) but do not want to exclude folks using iOS 3.0. Is there a way to check to iOS version of a device at runtime so that I can make a decision as to which statement to use?
Simpler solution for anyone who'll need help in the future:
NSArray *versionCompatibility = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ( 5 == [[versionCompatibility objectAtIndex:0] intValue] ) { /// iOS5 is installed
// Put iOS-5 code here
} else { /// iOS4 is installed
// Put iOS-4 code here
}
In many cases you do not need to check iOS version directly, instead of that you can check whether particular method is present in runtime or not.
In your case you can do the following:
if ([[UIView class] respondsToSelector:#selector(animateWithDuration:animations:)]){
// animate using blocks
}
else {
// animate the "old way"
}
to conform to version specified in system defines
//#define __IPHONE_2_0 20000
//#define __IPHONE_2_1 20100
//#define __IPHONE_2_2 20200
//#define __IPHONE_3_0 30000
//#define __IPHONE_3_1 30100
//#define __IPHONE_3_2 30200
//#define __IPHONE_4_0 40000
You can write function like this
( you should probably store this version somewhere rather than calculate it each time ):
+ (NSInteger) getSystemVersionAsAnInteger{
int index = 0;
NSInteger version = 0;
NSArray* digits = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
NSEnumerator* enumer = [digits objectEnumerator];
NSString* number;
while (number = [enumer nextObject]) {
if (index>2) {
break;
}
NSInteger multipler = powf(100, 2-index);
version += [number intValue]*multipler;
index++;
}
return version;
}
Then you can use this as follows:
if([Toolbox getSystemVersionAsAnInteger] >= __IPHONE_4_0)
{
//blocks
} else
{
//oldstyle
}
Xcode 7 added the available syntax making this relatively more simple:
Swift:
if #available(iOS 9, *) {
// iOS 9 only code
}
else {
// Fallback on earlier versions
}
Xcode 9 also added this syntax to Objective-C
Objective-C:
if (#available(iOS 9.0, *)) {
// iOS 9 only code
} else {
// Fallback on earlier versions
}
Most of these solutions on here are so overkill. All you need to do is [[UIDevice currentDevice].systemVersion intValue]. This automatically removes the decimal, so there is no need to split the string.
So you can just check it like:
if ([[UIDevice currentDevice].systemVersion intValue] >= 8) {
// iOS 8.0 and above
} else {
// Anything less than iOS 8.0
}
You can also define a macro with this code:
#define IOS_VERSION [[UIDevice currentDevice].systemVersion intValue];
or even include your check:
#define IOS_8PLUS ([[UIDevice currentDevice].systemVersion intValue] >= 8)
Then you just need to do:
if (IOS_8PLUS) {
// iOS 8.0 and above
} else {
// Anything less than iOS 8.0
}
Discouraged is not the same as deprecated.
If you need to support earlier versions of iOS that do not have the block based methods, there is nothing wrong with using the older methods (as long as they haven't been removed, of course).
You can use the version of the Foundation framework to determine the current system version.
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1){
//for earlier versions
} else {
//for iOS 7
}
For my purposes I've written a tiny library that abstracts away the underlying C calls and presents an Objective-C interface.
GBDeviceDetails deviceDetails = [GBDeviceInfo deviceDetails];
if (deviceDetails.iOSVersion >= 6) {
NSLog(#"It's running at least iOS 6"); //It's running at least iOS 6
}
Apart from getting the current iOS version, it also detects the hardware of the underlying device, and gets info about the screen size; all at runtime.
It's on github: GBDeviceInfo. Licensed under Apache 2.
Put this in your Prefix.pch file
#define IOS_VERSION [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:#"."] firstObject] intValue]
And then you can check iOS versions like:
if(IOS_VERSION == 8)
{
// Hello 8!
}
else
{
// Hello some other version!
}
Off course if you can use feature detection (and it makes sense for your use case) you should do that.
In MonoTouch:
To get the Major version use:
UIDevice.CurrentDevice.SystemVersion.Split('.')[0]
For minor version use:
UIDevice.CurrentDevice.SystemVersion.Split('.')[1]
A bit nicer and more efficient adaptation to the above solutions:
-(CGPoint)getOsVersion
{
static CGPoint rc = {-1,-1};
if (rc.x == -1) {
NSArray *versionCompatibility = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
rc.x = [versionCompatibility[0] intValue];
rc.y = [versionCompatibility[1] intValue];
}
return rc;
}
now you can
if ([self getOsVersion].x < 7) {
}
HTH

iPhone 4 detection... on simulator

I need to detect if the user is using an iPhone 4, but I need this to work on the simulator (cause Apple forgot my country and there's no sign of iPhone 4 here soon).
I found this
http://www.clintharris.net/2009/iphone-model-via-sysctlbyname/
but running this on the simulator it does not detect the correct version. I mean, Xcode 3.2.3 has two simulators (3G/3GS and 4). I was expecting the detection method to tell me the correct version I am using... but instead it tells me "iphone simulator"...
Is there any way to do that?
thanks.
You don't need to detect the system version in your case.
Suppose an image is named foo.png, then you just need to add
foo~ipad.png for iPad
foo#2x~iphone.png for iPhone 4
and load the image with [UIImage imageNamed:#"foo.png"]. See the iPhone Application Programming Guide for detail.
I think it would be better to check for the feature you require, rather than a specific device. This is certainly what Apple recommends, as it gives you insurance when new devices roll around!
In this case, would it work to check the size of the screen, and use that to determine if you need to scale your image?
[[UIScreen mainScreen] bounds]
Hardware Availability and State
If a hardware feature (for example,
a gyroscope) is not available on a
device, calling a start method related
to that feature has no effect. You can
find out whether a hardware feature is
available or active by checking the
appropriate property; for example, for
gyroscope data, you can check the
value of the gyroAvailable or
gyroActive properties.
Use
#property(readonly, nonatomic, getter=isGyroAvailable) BOOL gyroAvailable
of class CMMotionManager.
See
#property (nonatomic, readonly, retain) NSString *systemVersion;
// It equal to #"4.0" on iOS 4.0
and
#property (nonatomic, readonly, retain) NSString *model;
// Possible examples of model strings are #”iPhone” and #”iPod touch”
of class UIDevice.
From Erica Sudan:
- (NSString *) platform
{
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *machine = malloc(size);
sysctlbyname("hw.machine", machine, &size, NULL, 0);
/*
Possible values:
"iPhone1,1" = iPhone 1G
"iPhone1,2" = iPhone 3G
"iPhone2,1" = iPhone 3GS
"iPhone3,1" = iPhone 4
"iPod1,1" = iPod touch 1G
"iPod2,1" = iPod touch 2G
*/
NSString *platform = [NSString stringWithCString:machine];
free(machine);
return platform;
}
Or, if you just need to detect if it's a high res screen, you can use:
UIScreen *screen = [UIScreen mainScreen];
BOOL isHighRes;
if ([screen respondsToSelector:#selector(scale)]) {
isHighRes = ([screen scale] > 1);
} else {
isHighRes = NO;
}
Mike, you can know if the user is using an iPhone 4 by using preprocessor instructions. For example:
#ifdef __IPHONE_4_0
// Do some work for iPhone 4 device
#else
// Do some work for non iPhone 4 device
#endif
I hope it can help you.