Check if an overloading method exist in device iOS platform - iphone

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?

Related

Method UIToolbar.setItems doesn't work on iOS 6

I have the following code that works good on iOS 5.1 to replace buttons on the toolbar:
[(UIToolbar*)toolbar setItems:itemsArray];
But compiled application doesn't work on iOS 6. I have compiled sources with xXode 4.5 with iOS 6 support but the error is the same:
2012-09-27 16:31:13.537 Linux[2633:907] -[UIWebFormAccessory setItems:]: unrecognized selector sent to instance 0x1d886ad0
2012-09-27 16:31:13.540 Linux[2633:907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIWebFormAccessory setItems:]: unrecognized selector sent to instance 0x1d886ad0'
*** First throw call stack:
(0x361032a3 0x3441397f 0x36106e07 0x36105531 0x3605cf68 0x775c5 0x33bbda6f 0x360d85df 0x360d8291 0x360d6f01 0x36049ebd 0x36049d49 0x365862eb 0x37428301 0x7538d 0x75328)
libc++abi.dylib: terminate called throwing an exception
(lldb)
How to fix the issue?
Linked issue: How to replace buttons on a toolbar under UIWebView keyboard on iOS 6?
Thanks a lot for the help!
Even if it is a UIToolbar, which it might not be any longer, you're obviously trying to call a method (or "send a message") that doesn't exist. The solution is to not do that since the method won't just reappear out of nothing once you try hard enough.
It may be the case that there's another way to continue doing what you're trying to do by finding another fitting method on this undocumented type. However, maybe that will also break someday like this just broke. If they don't document something, yes, it means you can still use it (at least up until you send it for review), but it also means that it might break at any time.
A long term solution is to work out a way to bring up your own interface which you can control yourself. Knowing where you want to integrate, I don't suppose it's very easy. I think I saw another question about that here on Stack Overflow a few days ago saying to detect touches, stop editing and take over the UI yourself (although it doesn't really play well with cursor positioning, copy/paste menus and so on).
Either way, you'll have to devise a new solution that's not so brittle.
UIWebFormAccessory is not a UIToolbar on iOS6. If you want to mess with the form accessory toolbar, check out the "findVirginWebKeyboardToolbar" answer to your related question: https://stackoverflow.com/a/12865353/199267
are you sure the toolbar in this specific case is actually a UIToolbar? I would guess it's a casting issue.
I do the following in one of my classes, and it definitely works in iOS6
NSMutableArray *items = [NSMutableArray arrayWithArray: self.topToolbar.items];
[items insertObject:barButtonItem
atIndex:0];
self.topToolbar.items = items;

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++

Dealing with deprecated methods in 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).

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.

XCode AutoComplete current iPhone SDK, non-deprecated version?

Is there a way to configure XCode to autocomplete Cocoa methods with the most current, non-deprecated versions?
For instance
NSString *myString = #"Hello";
//xcode sets autocomplete to look like this
[myString writeToFile:arg1 atomically:arg2];
//however that gets a warning from the debugger
//the method is deprecated. the new method is:
[myString writeToFile:arg1 atomically:arg2 encoding:arg3 error:arg4];
I haven't mastered the memorization yet and I have been moving along by just using autocomplete and checking documentation when there is a problem. I wonder why the default xcode configuration for the newest iPhone SDKs autocomplete with deprecated methods. Can it be changed?
When typing and you see autoComplete start to show the next part, hit the escape key, and you can see the available completions. Type one letter and see a bunch. Hit escape again to hide it.
But that doesn't really answer your question on deprecated methods...