This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Best way to programmatically detect iPad/iPhone hardware
How can I differentiate the iPad and iPhone programmatically?
It seems for me that the question is a duplicate, but I'll try to brief all I know about device type and iOS version detection.
There are several methods based on which information you want to receive, whether it just device type (iPhone, iPod or iPad) or iOS version.
Here is code for detecting device type (returns i386 in case of Simulator):
#import <sys/utsname.h>
+ (NSString *)getDeviceType {
struct utsname systemInfo;
return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8Encoding];
}
And here is iOS version detector:
+ (float)getOSVersion {
return [[[UIDevice currentDevice] systemVersion] floatValue];
}
And OS detector for compiler:
#ifdef __IPHONE_4_0
//this part of code will be running on devices with os iOS4+
#else
//this part of code will be running on devices with os _UNDER_ iOS4+
#endif
Also, nobody proibits us to use
#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED > 40000
//this part of code will be running on devices with os iOS4+
#endif
Related
I need to make a connection to my server to get some JSON data and I have to support both iOS 6 and iOS 7.
Should I create two classes? One with NSURLSession for iOS 7 and one with NSURLConnection for iOS 6? Or should I just use NSURLConnection for both of them?
What benefit would you gain by creating two separate classes that do essentially the same thing? If you can't use NSURLSession because it's only supported in iOS 7, and you can get the same functionality using NSURLConnection, which works in both, then just use NSURLConnection. You will have less code to maintain.
Great question. In fact I had the same question and researched it quite a bit and I think this is a good place to use a protocol (a.k.a. interface in other languages). This is based off of the quote "Program to an interface, not an implementation" from the famous "Gang of Four" Patterns Book. I think it's best to try and code for the future so I never get hammered if they decide to deprecate something (which isn't the case here, but you never know).
Instead of writing classes, write a protocol that defines the methods you want to use and then create 2 different classes that implement those methods. In your app you would make a pointer that can point to any class that implements all of that protocols methods and then each implementing class can use whatever frameworks/libraries/other code they want to make that happen.
As an example, you could create a Server protocol like this:
// Server.h
#protocol Server <NSObject>
#required
- (void)callService:(NSString *)service withData:(NSData *)data;
#end
and then create a RestServer class like this:
// RestServer.h
#import "Server.h"
#interface RestServer : NSObject <Server>
#end
// RestServer.m
#import "RestServer.h"
#implementation RestServer
- (void)callService:(NSString *)service withData:(NSData *)data {
// Code using REST
}
#end
and then create another class like SoapServer:
// SoapServer.h
#import "Server.h"
#interface SoapServer : NSObject <Server>
#end
// SoapServer.m
#import “SoapServer.h"
#implementation SoapServer
- (void)callService:(NSString *)service withData:(NSData *)data {
// Code using SOAP
}
#end
Code your main app to just use a pointer to the interface and now you can swap classes without having to change your main code:
// SomeViewController.m
#import “Server.h”
#import “RestServer.h”
#import “SoapServer.h”
…
- (void)someMethod() {
id<Server> myServer;
if ([self shouldIUseSoap])
myServer = [[SoapServer alloc] init];
else
myServer = [[RestServer alloc] init];
[myServer callService:#"loginUser" withData:[self getData]];
}
Now you can change server classes whenever you want and never have to go hunt down all the places in your code where you make calls to callService:withData:. THIS IS THE BENEFIT OF PROGRAMMING TO INTERFACES!
I used Rest vs Soap because I figured people newer to Objective-C might understand that better, but in your case you’d maybe have a ConnectionServer vs SessionServer or something like that.
Another good read on programming to interfaces/protocols can be found here: https://stackoverflow.com/a/384067/504873
If you have to use NSURLCredentialPersistenceForSession if you have to get into a Windows Authentication network...then using NSURLConnection will create multiple problems for you. I'm going through the pain right now and have come to the conclusion that I need both to support iOS 7. Basically, if you use NSURLConnection and willSendRequestForAuthenticationChallenge, you will find that in iOS 7, your session will end with a mind of it's own (seems like a 30 second mind span). So if you have to persist a credential to access more SOAP or whatever, welcome to the terror dome! I will report back to you with code if I find a smooth solution.
At time of writing, NSURLConnection has been deprecated in OS X 10.11 and iOS 9.0 but my Apps need to support OS X 10.7 and iOS 6.
So now you HAVE to use NSURLSession for ongoing projects BUT also support the now deprecated NSURLConnection class for supported legacy OS releases!
I would these days vote for TenaciousJay solution with Compiler warning suppression around the NSURLConnection class implementation.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/* NSURLConnection code here */
#pragma GCC diagnostic pop
The benefit you would you gain by creating two separate classes that do essentially the same thing is that you can eventually CUT off the old, deprecated solution when you can finally drop support for legacy OS releases.
My code decision to use one class or the other would not be based upon some class property but on the result of a Macro like:
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
for iOS or for OS X:
NSString *systemVersion = nil;
if ([[NSProcessInfo processInfo] respondsToSelector:NSSelectorFromString(#"operatingSystemVersion")]) {
NSOperatingSystemVersion operatingSystemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
systemVersion = [NSString stringWithFormat:#"%ld.%ld.%ld", (long)operatingSystemVersion.majorVersion, (long)operatingSystemVersion.minorVersion, (long)operatingSystemVersion.patchVersion];
} else {
SInt32 versionMajor=0, versionMinor=0, versionPatch=0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Gestalt(gestaltSystemVersionMajor, &versionMajor);
Gestalt(gestaltSystemVersionMinor, &versionMinor);
Gestalt(gestaltSystemVersionBugFix, &versionPatch);
#pragma GCC diagnostic pop
systemVersion = [NSString stringWithFormat:#"%ld.%ld.%ld", (long)versionMajor, (long)versionMinor, (long)versionPatch];
}
NSLog(#"[Line %d] %s OS X Runtime Version: '%#'", __LINE__, __PRETTY_FUNCTION__, systemVersion);
I'd like to know whether my app is being run on device or simulator at run time. Is there a way to detect this?
Reason being to test bluetooth api with simulator:
http://volcore.limbicsoft.com/2009/09/iphone-os-31-gamekit-pt-1-woooohooo.html
#if TARGET_OS_SIMULATOR
//Simulator
#else
// Device
#endif
Pls refer this previous SO question also What #defines are set up by Xcode when compiling for iPhone
I created a macro in which you can specify which actions you want to perform inside parentheses and these actions will only be performed if the device is being simulated.
#define SIM(x) if ([[[UIDevice currentDevice].model lowercaseString] rangeOfString:#"simulator"].location != NSNotFound){x;}
This is used like this:
SIM(NSLog(#"This will only be logged if the device is simulated"));
TARGET_IPHONE_SIMULATOR is defined on the device (but defined to false). and defined as below
#if TARGET_IPHONE_SIMULATOR
NSString * const DeviceMode = #"Simulator";
#else
NSString * const DeviceMode = #"Device";
#endif
Just use DeviceMode to know between device and simulator
Check if simulator
#if TARGET_IPHONE_SIMULATOR
// Simulator
#endif
Check if device
#if !(TARGET_IPHONE_SIMULATOR)
// Device
#endif
Check for both
#if TARGET_IPHONE_SIMULATOR
// Simulator
#else
// Device
#endif
Please note that you should not ifdef on
TARGET_IPHONE_SIMULATOR because it will always be defined to either 1 or 0.
From XCode 9.3+ , Swift
#if targetEnvironment(simulator)
//Simulator
#else
//Real device
#endif
Helps you to code against device type specific.
You can use the TARGET_IPHONE_SIMULATOR preprocessor macro to distinguish between device and simulator targets.
Use this below code:
#if targetEnvironment(simulator)
// iOS Simulator
#else
// Device
#endif
Works for Swift 4 and Xcode 9.4.1
if anyone is looking for Unity solution i did this, the only way i found how.
using System.Globalization;
public static bool IsArm() {
return CultureInfo.InvariantCulture.CompareInfo.IndexOf(SystemInfo.processorType, "ARM", CompareOptions.IgnoreCase) >= 0;
}
My app support iOS 5+. Now I want to add facebook and twitter.
I added social.framework as optional and on facebook btn i check
if([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
NSLog(#"Facebook iOS 6 avaliable");
}
else
{
NSLog(#"Feature not supported"); // for iOS 5 users
}
same for twitter. But iOS 6 Simulator works fine but iOS 5 simulator gives error. any help or tutorial for adding facebook and twitter share on iOS 5 and iOS 6 both.
EXC_BAD_ACCESS (code=2, address=0x0) isAvailableForServiceType:SLServiceTypeFacebook
isAvailableForServiceType:SLServiceTypeTwitter
after updating project for answer 1 go this error.
here is prefix file
EXC_BAD_ACCESS (code=2, address=0x0)
So this error is a "segmentation fault", because the Social framework is an iOS6-only framework. Since you used weak linkage (that's what adding the framework as "optional" means), the SLComposeViewController class is Nil (i. e. it actually points to the invalid memory address 0x0), so any function you will try to call on it will most likely result in a segmentation fault (since dereferencing this address is not possible).
What you have to do is check this class to be a valid pointer:
if (NSClassFromString(#"SLComposeViewController") != Nil) {
// iOS 6
} else {
// iOS 5, Social.framework unavailable, use Twitter.framework instead
}
The Social framework (SLComposeViewController) was only introduced in iOS 6. In iOS 5 the only native connection to any social network was Twitter and the TWTweetComposeViewController class. iOS 6 introduced the Social framework with pre-existing Twitter support and new Facebook and Sina Weibo integration.
So on iOS 5 you cannot actually make any reference or call to SLComposeViewController, you will need to use conditions to see which version (iOS 5 or 6) the user's device is running then make any operations/conditions.
The code if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) is used to see if the user has setup a Facebook account in the Settings application.
Yes, so you add the Twitter framework for iOS 5 compatibility, make sure Social framework is set to optional by the way.
To check what version the device is running, add this to your MyApp-Prefix.pch file:
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
Then you can use it in any class because the prefix file is automatically imported to all classes:
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"5.0") && SYSTEM_VERSION_LESS_THAN(#"6.0")) {
NSLog(#"This is called when device is running iOS 5, 5.0.1, 5.1 etc.");
}
else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"6.0")) {
NSLog(#"iOS 6.0, 6.0.1, 6.0.2, 6.1 etc.");
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I programmatically determine if my app is running in the iphone simulator?
How I can check in XCode 4 with constant if my program is running in simulator o device?
Something like this:
#ifdef RUNING_ON_DEVICE
#else
#endif
There are a couple of options
Preprocessor macro:
#if TARGET_IPHONE_SIMULATOR
//is sim
#elif TARGET_OS_IPHONE
//is real device
#else
//unknown target
#endif
Or, if you'd rather do it in some arbitrary method:
if ([[[UIDevice currentDevice] model] isEqualToString:#"iPhone Simulator"]) {
//device is simulator
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Determine device (iPhone, iPod Touch) with iOS
How to check iOS version?
I am using this function to get the device name
NSString *device=[UIDevice currentDevice].model;
it returns me, for example, "iPhone" .
is there a way to get the device version, for example, "iPhone 4S".
#import <sys/utsname.h>
- (NSString *)deviceModel
{
struct utsname systemInfo;
uname(&systemInfo);
return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
}
try
[[UIDevice currentDevice] platformString]
That will normally return if it is iPhone 4S...