Dealing with deprecated methods in iPhone - iphone

How do you deal with deprecated methods in iPhone that require you to use a newer method, not available in older versions?
Consider the case of setStatusBarHidden:animated:, which was deprecated in iOS 3.2. The documentation points you to use setStatusBarHidden:withAnimation:, which is only available in iOS 3.2 or later.
If I understand correctly, this means that to target all devices (iOS 3.0 or later), I have to ask first if setStatusBarHidden:withAnimation: is available. If it is, use it. If not, use the deprecated method. But I would still get a warning of deprecation.
Is this correct (please say it isn't!)? If it is, is there any way to suppress this deprecation warning, or to indicate the compiler that I have already handled the problem?

I found a similar question that assumes that yes, this is the correct way of dealing with deprecated methods, and no, there is no way to suppress deprecation warnings on a per-case basis, but there are hacks to mislead the compiler.
To deal with the example case, I decided to create an util class using one of these hacks:
#protocol UIApplicationDeprecated
- (void) setStatusBarHidden:(BOOL)hidden animated:(BOOL)animated;
#end
#implementation UIUtils
+ (void) setStatusBarHidden:(BOOL)hidden animated:(BOOL)animated {
if([[UIApplication sharedApplication] respondsToSelector:#selector(setStatusBarHidden:withAnimation:)]) {
[[UIApplication sharedApplication] setStatusBarHidden:hidden withAnimation:animated ? UIStatusBarAnimationSlide : UIStatusBarAnimationNone];
} else {
id<UIApplicationDeprecated> app = (id)[UIApplication sharedApplication];
[app setStatusBarHidden:hidden animated:animated];
}
}
#end
If I'm not mistaken using respondsToSelector is costly. This could be optimized for performance to remember if the new selector is present after the first query, thus avoiding the need for reflection in subsequent calls.
Coming from a Java background, I find this way of dealing with deprecation appalling and I still can't believe that this is how iOS designers expect us to deal with this problem. More thoughts on the subject will be much appreciated.

Probably there is a better answer, but what I did once was:
1 check if the deprecatedMethod is available. (using respondsToSelector: method)
2 if yes then call that method using objective-c runtime function:
id objc_msgSend(id theReceiver, SEL theSelector, ...)
when using this function the compiler won't give you any warnings :)
3 other wise use the new method

Invoking method this way:
id objc_msgSend(id theReceiver, SEL theSelector, ...)
will be better choise in case you want to omit warning that UIApplication may not respond to setStatusBarHidden:withAnimation: method (in iOS 3.0 or later).

Related

How to fix error – "No Visible #interface for ARCamera"?

I'm trying to build a project that I downloaded from git and I got some errors in the Xcode beta 9.
I noticed that there are some things that are deprecated like ARWorldTrackingSessionConfiguration so I changed them and they were fixed. But I get an error that I can't fix, this is the part from the code:
matrix_float4x4 projectionMatrix = [frame.camera projectionMatrixWithViewportSize: nativeSize
orientation:[[UIApplication sharedApplication] statusBarOrientation]
zNear:(CGFloat)unityCameraNearZ
zFar:(CGFloat)unityCameraFarZ];
I could not fix this and I don't know what to do.
the error for that is this:
No visible #interface for 'ARCamera' declares the selector 'projectionMatrixWithViewportSize:orientation:zNear:zFar
Hope you can help me with this issue?
Thank you.
First of all you should update your XCode from beta to a stable version.
As for
No visible #interface for 'ARCamera' declares the selector 'projectionMatrixWithViewportSize:orientation:zNear:zFar
Here is official Apple documentation about ARCamera class which shows that there is no method projectionMatrixWithViewportSize:orientation:zNear:zFar and it's most possibly was changed to projectionMatrixForOrientation:viewportSize:zNear:zFar:. Signatures of this two methods requires the same parameters, so it won't be problem to replace the old method with a new one.

Theos with iOS SDK 5 and method porting

So I am attempting to bring the iOS 5 SDK to the Theos Makefile system. I have the following things working: Private Frameworks, Multitasking from UIKit. Since Theos uses SDK 3. This jump to SDK 5 breaks a few methods as they're deprecated. Keep in mind that I'll be using RPetrich's headers on GitHub for this. With that in mind, I'm trying to add the following dismissal code to the UIViewController header.
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_5_0);
This makes my compiler complain about the (void (^) (void)) part. I've tried replacing it with BOOL and just a regular void and then just calling nil when using the method. Doesn't work that way. I wanted to know if there was a way I can successfully compile with this method, or if I can somehow use dismissModalViewControllerAnimated: again. Some reason I can still use presentModalViewController:animated: and it says they both WILL be deprecated. Any suggestions?
change default compiler gcc/g++ to apple's clang/clang++

Error when registering for Multiple Remote Notification Types

XCode is driving me nuts, when I register for multiple notification types:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge];
or
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge)];
It throws and error not a warning:
error: Semantic Issue: Cannot initialize a parameter of type 'UIRemoteNotificationType' with an rvalue of type 'int'
Even though this is the same line that everyone uses (even Apple in their demos). I'm using the iOS 5 SDK (first one that came out after release of iOS 5) & XCode 4.2. The project is a older project (XCode 3 & iOS 4) that is being upgraded and targeted for iOS 5.
I had this problem too. The trick is if this code is in a .mm file (Objective C++), this error occurs. If you aren't using any C++ features, change the filename extension from .mm to .m and it will compile OK.
Try casting to UIRemoteNotificationType:
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationType)(UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge)];
For the record I was never able to solve this problem completely. It is definitely a problem with the developer tools. The line in my UIApplicationDelegate didn't work. I was able to work around this by placing this line in my MainViewController rather than my ApplicationDelegate.
put parentheses around the parameters like
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeSound|UIRemoteNotificationTypeBadge)];

Check if an overloading method exist in device iOS platform

There are 2 "writeImageToSavedPhotosAlbum" methods in ALAssetsLibrary Class:
- (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef
metadata:(NSDictionary *)metadata
completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock
(available on iOS 4.1+)
- (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef
orientation:(ALAssetOrientation)orientation
completionBlock:(ALAssetsLibraryWriteImageCompletionBlock)completionBlock
(available on iOS 4.0+)
I am using the 1st one (need iOS 4.1) in my code and it will crash on iOS 4.0 device. I am trying to use respondsToSelector to check which method is supported, however looks like the selector only check the method name, not the parameters.
I read some suggestions and feel it might not good by purely check on OS version, so is there anything similar to respondstoselector that can help me solve this problem?
You misunderstand the Objective-C method naming system. The selector is the combination of all foo:bar:baz: combined.
So, in this case, there is no method called writeImageToSavedPhotosAlbum. The first one is, as a selector, corresponds to
#selector(writeImageToSavedPhotosAlbum:metadata:completionBlock:)
and the second one is
#selector(writeImageToSavedPhotosAlbum:orientation:completionBlock:)
In your code, check whether the first selector is available or not, as in
if([obj respondsToSelector:#selector(writeImageToSavedPhotosAlbum:metadata:completionBlock:)]){
....
}
This should distinguish whether the first one is available or not.
These methods have different names, so you can test them separately.
if ([assetsLibrary respondsToSelector:
#selector(writeImageToSavedPhotosAlbum:metadata:completionBlock:)]) {
// Now you can safely use this method.
}
If you wanted to test the other one you would use #selector(writeImageToSavedPhotosAlbum:orientation:completionBlock:).
You can then differentiate them with os version. How about it?

conditionally import framework

well to begin with I'm sure this is a simple question.
I am developing an iPhone app with the iAd Framework, which only runs for iOS 4.0 or higher.
Still, I wanna choose a iPhone OS 3.0 deployment target, which causes everything to crash.
How do I conditionally include the iAd framework?
...I mean, it would be something like:
...if([[UIDevice currentDevice] systemVersion]>=4.0]) #import
Obviously this won't work because I don't know the correct syntax. Also:
How do I conditionally declare an AdView* variable?
How do I conditionally handle this AdView* variable in my implementation file.
If you guys could help me, I will be very well impressed.
Thanks
You don't need to change your include, you need to make the iAd (or any other new framework) linked weakly:
In your target, find iAd in the linked frameworks and change its "Role" from "Required" to "Weak".
To handle the variable conditionally, use NSClassFromString function, like this:
Class AdClass = NSClassFromString(#"ADBannerView");
if(AdClass) {//if the class exists
ADBannerView* myAd = [[AdClass alloc] initWithFrame:CGRectZero];
// do something with the ad
}
If OS is older than iOS 4.0, AdClass will be nil and the code won't execute. Note that using ADBannerView* as the type of the variable shouldn't cause any problems, as it's just a hint for a compiler and is the same as id after compilation.