AVCaptureDevice keeps crashing my iPod Touch with OS 3 - iphone

I made some conditional coding in my app to check for AVCaptureDevice, but it still crashes my iPod Touch (iOS 3.1.3) with this message:
dyld: Symbol not found: _OBJC_CLASS_$_AVCaptureDevice
Referenced from: /var/mobile/Applications/4286D40F-9E33-49AB-9AD9-4F66EB9331A5/TestApp.app/TestApp
Expected in: /System/Library/Frameworks/AVFoundation.framework/AVFoundation
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
mi_cmd_stack_list_frames: Not enough frames in stack.
mi_cmd_stack_list_frames: Not enough frames in stack.
In my code, I do conditional checks like this:
#if (!TARGET_IPHONE_SIMULATOR)
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000 // __IPHONE_4_0
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
// ... more code
#endif
#endif
I'm checking here and the other place in code that uses AVCaptureDevice with this same conditional.
I'm guessing the iPods older iOS version isn't able to link to the newer library, so I how do I correct it?

Try checking if you have AVfoundation.framework added to your Frameworks
In my opinion, it's the most probable reason for the error

First, you cannot use preprocessor directives to select which code to run here. The check has to happen at runtime, not at compile time. So you must use NSClassFromString(), -respondsToSelector: or similar techniques to do this.
Second, to make this compile, change your compiler to LLVM GCC as described by Marco Arment.

AVCaptureDevice is only available on iOS versions 4 and above. You have two options:
Check the system version and handle things appropriately:
UIDevice *device = [UIDevice currentDevice];
if([device.systemVersion floatValue]
NSLog(#"Not supported on this software version");
}else{
//Proceed Normally
}
Check for class availablility:
Class avcaptureclass = (NSClassFromString(#"AVCaptureDevice"));
if (avCaptureClass != nil){
//Proceed Normally
}else{
NSLog(#"Not supported on this software version.");
}

Related

Need to restrict my app to only run on devices with an L.E.D

I've built a flashlight app, how can I put a restriction in place so it will only install on devices with a L.E.D? I presume UIDeviceRequiredCapabilities, but not sure which key/value to use.
You can set the camera-flash key of the UIDeviceRequiredCapabilities properties to YES to make sure it will only install on devices that contain a "camera flash" (usually the torch)
Here is a complete answer: Turn on torch/flash on iPhone
To check if the device has the torch or not, use this code:
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if ([device hasTorch]) {
// The device has a torch
}

dyld: Library not loaded: /System/Library/Frameworks/Accounts.framework/Accounts

I am getting the following error while running an app on iOS simulator 4.2/4.3. It's working fine with iOS 5.
dyld: Library not loaded: /System/Library/Frameworks/Accounts.framework/Accounts
Referenced from: /Users/User/Library/Application Support/iPhone Simulator/4.3/Applications/FBFD053F-E816-4114-AFEB-D90A6A67259B/SampleApp.app/SampleApp
Reason: image not found
I am using the AssetsLibrary and OpenCV frameworks in my app.
I am not getting the cause of error.
Better yet you could keep it but change it from Link Binary With Libraries: from required to optional.
Then in your code skip the framework methods when in a 4.x device.
You are getting this error because Accounts.framework is only available in iOS 5.0 or later. So you are not able to run it on iOS 4.2/4.3.
You can also mark Accounts.framework as optional. In Xcode, select Targets > Build Phases > Link with binary libraries > Accounts.framework and mark as optional.
Also please make sure to skip this code(code that requires iOS 5.0 or greater) in iOS 4.3. You can use the following code to check this :
NSString *reqSysVer = #"5.0";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending) {
//Add any code that requires iOS 5.0
}

ios: add printing, but keep compatibility with ios 3

i'm trying to add printing features to an ios app.
while printing itself works fine, and the app works on ios > 4, i haven't figured out yet how to keep the ios 3.1 compatibility...
i guess the issue is this: completionHandler:(UIPrintInteractionCompletionHandler)
A block of type UIPrintInteractionCompletionHandler that you implement to handle the
conclusion of the print job (for instance, to reset state) and to
handle any errors encountered in printing.
once i add the block:
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
the app won't even launch on iOS 3.1
probably because blocks aren't available there.
yes, i made sure that this code won't be run when launched on iOS 3.1...
if (([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.2) && ([UIPrintInteractionController isPrintingAvailable]))
so i wonder if there's a way to have printing support for iOS >4.2, but keeping it to run on iOS 3.1?
maybe there's a way to use a method instead of the "block"?
or how would be the correct way to have printing available on supported iOS devices, and remain backwards compatible to iOS 3.1?
just add -weak_framework UIKit to the project settings under "Other Linker Flags" and make sure you use conditional code for printing API.
Conditional code should check feature availability, not OS version:
if (NSClassFromString(#"UIPrintInteractionController")){
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
};
}
Set your project target to iOS 3, and you're good to go.
The best practice for detecting if AirPrint is available is to use NSClassFromString. If you use this method in general, then you always know if exactly the class you want is available, without having to hard-code which features correspond with which version. Example code:
Class printControllerClass = NSClassFromString(#"UIPrintInteractionController");
if (printControllerClass) {
[self setupCanPrintUI];
} else {
[self setupCannotPrintUI];
}
That way your app can still work on previous iOS versions, although it won't be able to print from them.
I've been able to use this technique and run it on an iOS 3.0 device without any problems with the block code (the ^-based stuff). In my build settings, I have the Base SDK set to iOS 4.2, and the Deployment Target set to iOS 3.0.
I posted a sample Xcode project at the end of this blog post on printing in iOS. This is the project that successfully runs for me on a device with iOS 3.0 and another device with iOS 4.2. You may have to change the bundle identifier in the info.plist to get the code-signing to work for you, but that's independent of the printing stuff.
Set Deployment Target in your Project Settings to iOS 3.x. However, set the Base SDK to 4.2. Now you can use the 4.2 classes and iPhones running 3.x can install your app too.
Keep in mind that when you use a 4.2 class on an iPhone 3.x, the application will crash (so keep checking the system version on-the-go).
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare:#"3.2" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending && [[UIDevice currentDevice]isMultitaskingSupported]) {
// >4.2
}
else {
//< 4.2
}
Note:
also change UIKit framework setting from "required" to "weak" this will help you to run application on iOs < 4.2 as well as iOs >= 4.2

How to test for the existance of a constant when creating a iPhone universal binary

I am trying to create a universal binary that supports multitasking on the iPhone 4 and can still run on the iPad.
I know how to avoid compile errors for different versions of the iPhone IOS by checking if a class exists by using NSClassFromString and "respondToSelector", but is there a way to check for the existence of constants like UIBackgroundTaskInvalid?
I of course can use #IFDEF, but I want to avoid this.
You do it as follows:
if (NULL != &UIBackgroundTaskInvalid) {
//do multitasking stuff here
} else {
// don't do multitasking stuff here.
}
Basically you want to verify that the address of that variable exists.
Update: To be clear, you can't really use an #ifdef for this since you will build with a version of the SDK that contains the symbols.
It's probably sufficient to test for the existence of a method that you know is associated with the constant.
The preferred method to check for multitasking iOS is to see if UIDevice responds to isMultitaskingSupported, like this:
//----------------------------------------------------------------------
// returns YES if multitasking is available (iOS 4.0 or >)
//----------------------------------------------------------------------
BOOL hasMultitasking()
{
UIDevice* device = [UIDevice currentDevice];
if ([device respondsToSelector:#selector(isMultitaskingSupported)]) {
return [device isMultitaskingSupported];
}
return NO;
}
If multitasking is supported then you can use those multitasking related constants, which you should have weak linked to.

How to target a specific iPhone version?

I've got some code I want to only execute on the latest iPhone SDK (3.0), however I can't seem to figure out a way to target just 3.0 and ignore 2.2.1 etc. There is an ifdef statement, but it just seems to cover the entire iPhone:
#if TARGET_OS_IPHONE
Any help is appreciated.
You can use this #define to change what you build for each SDK...
#if __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_2_2
// iPhone 3.0 code here
#endif
And do this at run-time to run code for 3.0 and above:
float version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (version >= 3.0)
{
// iPhone 3.0 code here
}
I'd be careful with the floatValue return result:
[[[UIDevice currentDevice] systemVersion] floatValue]
As with any floats, it may not be exactly what you expect. When running the above on my system, confused why my conditional statement wasn't executing, I noticed the value returned was:
3.20000005
Recommend the solutions here instead: How to check iOS version?
Excerpt:
NSComparisonResult order = [[UIDevice currentDevice].systemVersion compare: #"3.1.3" options: NSNumericSearch];
if (order == NSOrderedSame || order == NSOrderedDescending) {
// OS version >= 3.1.3
} else {
// OS version < 3.1.3
}
UPDATE: When building & running on iPhone (4.3.1) using Xcode 4, this no longer seems to work for me. Also, I get __IPHONE_OS_VERSION_MIN_REQUIRED = 30200.
The iPhone Developer's Cookbook says you can also do:
#ifdef _USE_OS_4_OR_LATER
// code to compile for 4.0 or later
#else
// code to compile for pre-4.0
#endif
And, it seems to work for me. :)
Pretty sure you can also do:
#ifdef __IPHONE_3_0
// 3.0 code here
#endif
It's in Xcode's build options. The drop down on the top left corner that says something like "myapp - 3.0 | Debug"
Select the build you want and presto, your done.
Using the trick of adding OTHER_CFLAGS = "-g3 -save-temps -dD" from this answer, I found that the define __IPHONE_OS_VERSION_MIN_REQUIRED 20000 with a project targeted at 2.2.1. Perhaps that will work?
I'm fairly certain that the comment on the OP sums it up. You can't. Because a compile time directive cannot make a run-time decision. In Xcode, if you target 3.0, it won't run on a 2.2.1 phone. If you target 2.2.1, it won't compile because you have 3.0 specific code in there.
The only true solution would be two versions of your app, one of which is compiled for 3.0, and the other for 2.2.1.
Well, my two cents:
How about building your app with the latest version say 3.0 so you can exploit all the new & cool APIs and specifying the Deployment Target as the least recent version you want to support so guys out there who didn't take time out to upgrade their devices will stil run your app. In this case as shown above you need to check for least recent version of the SDK and provide alternate functionality to make your application backward compatible.
Regards,
Hardik