Modern way to deal with deprecations on iOS/macOS - ios

How to suppress deprecation warning within availability macro? I know availability is a great way to check for new APIs but I am struggling how to suppress deprecation warnings. What alternatives do I have other than those mentioned below? (1.pragma 2.performSelector)
MyModel *model;
if (#available(macOS 10.13, *)) {
NSError *error;
model = [NSKeyedUnarchiver unarchivedObjectOfClass:[MyModel class] fromData:metadata error:&error];
if (error) {
[[NSAlert alertWithError:error] runModal];
}
} else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
model = [NSKeyedUnarchiver unarchiveObjectWithData:metadata];
#pragma clang diagnostic pop
}
Alternatively use to suppress warning
if ([NSKeyedUnarchiver respondsToSelector:#selector(unarchiveObjectWithData:)]) {
model = [NSKeyedUnarchiver performSelector:#selector(unarchiveObjectWithData:) withObject:metadata];
}

You will only get a deprecation warning if you are using an API that was deprecated at or earlier than your target's Deployment Target.
NSKeyedUnarchiver unarchiveObjectWithData is deprecated as of macOS 10.14. You will only get a deprecation warning if your target's Deployment Target is macOS 10.14 or later. But the code you posted implies you wish to support macOS 10.12 or earlier.
NSKeyedUnarchiver unarchivedObjectOfClass:fromData:error: was added in macOS 10.13.
If you really only want a Deployment Target of macOS 10.13 or later then you don't need the if (#available(macOS 10.13, *)) or the else. Just use the new API and be done.
The code in your question (minus the pragmas) should only be used if you want to support macOS 10.12 or earlier. Then your target's Deployment Target needs to be set to macOS 10.12 or earlier. And in this case you don't need the pragmas and you won't get any deprecation warnings.

Related

How do i get rid of IOS version "is partial: introduced in IOS X" warnings in Xcode

So, i have some places where things are only available after a certain version. One example is some new NFC stuff i've introduced in my app:
#property(nonatomic, retain) NFCNDEFReaderSession *nfcSession;
I also have it in methods, where i get it even though i check for class availability, for example:
if ([NFCNDEFReaderSession class]){
my app works fine, but i get an xcode warning saying
NFCNDEFReaderSession is partial: introduced in iOS 11.0
I have looked around but haven't found a way to tell the compiler that it's fine and get rid of the warning.
Pointers much appreciated!
Add NS_AVAILABLE_IOS(11.0) to the end of the method name. For example:
- (BOOL)tableView:(UITableView *)tableView canHandleDropSession:(id<UIDropSession>)session NS_AVAILABLE_IOS(11.0) {
}
Method calls can be wrapped in the following to silence the new API warning
if (#available(iOS 11.0, *)) {}
You can silence specific warnings on parts of your code by adding Clang “pragmas” around it. In this case:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
// your code
#pragma clang diagnostic pop
Documentation: https://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas
To silence the warning, change the target's "Other warning flags" to either:
-Wno-partial-availability
-Wno-unguarded-availability
You can also turn off Unguarded availability in the project settings. If you're using Cocoapods, it's now on by default in the Pods project.

Using new iOS 10 API in compiled framework under XCode 7

My company is developing an iOS SDK, which uses the new CallKit APIs. The SDK (.framework) is compiled with XCode 8 / SDK 10.0.
However, some of out customers are still using XCode 7 - When I try to integrate our SDK under a XCode 7 project, I got the following error :
ld: framework not found CallKit for architecture arm64
However, I put some macro directive into the SDK code, to provide a CoreTelephony fallback, but event with this trick, the project's target does not compile with the message above.
Here is the directive example :
#ifdef __IPHONE_10_0
#import CallKit;
#endif
Do you have a trick to use a SDK compiled with iOS 10 API working under XCode 7 ?
EDIT
Find a way to manage that. The idea is to lazy load CallKit (runtime). I had to call performSelector instead of calling directly methods.
Here is some code :
// Lazy load CallKit framework to keep compatibility for XCode 7 SDK integration
if ([[AppKit sharedInstance] systemVersion] >= kIosSystemVersion10) {
NSBundle *b = [NSBundle bundleWithPath:#"/System/Library/Frameworks/CallKit.framework"];
_isCallKitFrameworkLoaded = [b load];
}
if (_isCallKitFrameworkLoaded) {
SEL callObserverDelegate = NSSelectorFromString(#"setDelegate:queue:");
if ([_callObserver respondsToSelector:callObserverDelegate]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
[_callObserver performSelector:callObserverDelegate withObject:self withObject:(__bridge id)(_callObserverQueue)];
#pragma clang diagnostic pop
}
} else {
// CoreTelephony fallback
}
CallKit is available from iOS 10 and later. Xcode 7 support upto iOS 9 only. If you need to use this framework, you need to update to latest Xcode(obviously Xcode8) which supports iOS 10.
So users who are having iOS 10 only can use this feature and not iOS 9.

Warning: unnecessary check for minimum deployment target

I have a Swift class which is linked against several targets with different deployment targets, the main project has iOS 7 minimum requirement and there is an extension with iOS 8 target.
Now when I compile project, the compiler throws warning on this line of code:
if #available(iOS 8.0, *) { ... }
"Unnecessary check for 'iOSApplicationExtension'; minimum deployment target ensures guard will always be true"
I have checked build settings options and found no switch to kill swift warnings.
I tried to define iOSApplicationExtension version target separately by this line but without success:
if #available(iOS 8.0, iOSApplicationExtension 8.0, *) { ... }
Is there any way to suppress this annoying message?
Found an ugly workaround to silence warning, but I hope there is a better way:
In iOS 8+ targets build settings, I defined a precompile flag in Build Settings -> Swift Compiler - Custom Flags -> Other Swift Flags:
-D iOS8target
Then I changed code to this way:
#if iOS8target
// iOS 8+ compatible code
#else
if #available(iOS 8.0, *) {
// repeat iOS 8+ compatible code again!
} else {
// iOS 7 code
}
#endif
It's not refactored and ugly, but it works!
UPDATE:
There is a swift compiler switch -suppress-warnings to omit all warnings. But it also suppress useful warnings.
Also if there is only one specific file which emits warnings, you can use -w flag in Building Phases pane. It will also suppress useful warnings but limited to one file.
The next release of Cocoapod (after 0.39.0) should have this issue addressed. Check this for more details.
Please check your deployment target into your General and set from 9.0
to 7.0 or less. this warning will remove automatically.

deprecated warnings in xcode and how to handle deprecation

if ([self respondsToSelector:#selector(dismissViewControllerAnimated:completion:)])
{[[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];} //post-iOS6.0
else {[self dismissModalViewControllerAnimated:YES];} //pre-iOS6.0
I'm doing the responds to selector (above) code to handle deprecated methods. That way my app is compatible with older versions of iOS, but I'm getting warnings in my code stating: "'dismissModalViewControllerAnimated:' is deprecated: first deprecated in iOS 6.0"
I personally don't like any warning in my code, but more importantly, I read somewhere that apple will complain about warnings in your code.
1) Will Apple complain about warnings in your code?
2) Am I handling deprecated methods correctly?
3) Is there way to turn deprecated method method warnings off?
Apple is unaware of any compile-time warnings you receive with your code.
Yes, you are handling this practice correctly. Clearly, in this case, you only need to go through this effort if you're supporting iOS prior to 5.0. But, in general, the technique for testing whether a method can be invoked and then calling the appropriate rendition is absolutely correct.
If you want to turn off the warning, you would simply temporarily suppress the warning and then turn it back on afterwards using the appropriate #pragma syntax:
if ([self respondsToSelector:#selector(dismissViewControllerAnimated:completion:)])
{
//post-iOS6.0
[self dismissViewControllerAnimated:YES completion:nil];
}
else
{
// pre-iOS6.0
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self dismissModalViewControllerAnimated:YES];
#pragma clang diagnostic pop
}
By the way, if you want to know what the -W code is for your particular warning, go to your Log Navigator, select the recent build that included the warning, and expand the log, and you'll see it there:
Also note that while you could suppress the warning like I've illustrated above, in practice, you rarely need to do so. Using your example, if your project's iOS deployment target was 4.3, you wouldn't get the warning. And if your deployment target was 6.0 or higher, you'd get that warning, but then again, you probably wouldn't need this conditional code to call dismissModalViewControllerAnimated because effective iOS 5.0, you can always use dismissViewControllerAnimated.
The only time that you'd need to suppress this warning in your code is if you have source code, to be included in projects in the future, for which you don't know what the deployment target will be. Using your example, if you don't know whether the above code will be included in a project with a 4.3 deployment target or a 5.0+ deployment target. In that case, this syntax is quite useful. But, then again, I you could also use conditional checks on __IPHONE_OS_VERSION_MIN_REQUIRED, e.g.:
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0
if ([self respondsToSelector:#selector(dismissViewControllerAnimated:completion:)])
{
//post-iOS5.0
[self dismissViewControllerAnimated:YES completion:nil];
}
else
{
// pre-iOS5.0
[self dismissModalViewControllerAnimated:YES];
}
#else
[self dismissViewControllerAnimated:YES completion:nil];
#endif
No
You should use the most recent methods unless you are specifically trying to support old iOS versions, then you should use the method you outlined above. "A method identified as deprecated has been superseded and may become unsupported in the future."
If you change the deployment target in your application target to 5.0, the deprecated warnings for iOS 5 not will be show as errors.
If you are really interested in backwards compatibility, there is a great tutorial by Ray Wenderlich here
Yes Many warnings are of present and dismiss view modally to fix that Replace:
in ios 6 these are:-
[self dismissViewControllerAnimated:NO completion:nil];
[self presentViewController:vc animated:NO completion:nil];

ios Facebook SDK Pragma, GCC error

I have to implement a Facebook sharing method... I watched the video, read a couple of tutors, etc...
1: I registered my app, downloaded the sdk, the samples are running fine
2: when i drag and drop the FacebookSDK.framework into my app (not a new app, it has custom frameworks), and include the #import into the desired class and the appdelegate, during the build, i keep getting the following error in FBRequest.h:
LLVM GCC 4.2 error
'#pragma' is not allowed here
LLVM GCC 4.2 error
instance variable '<unnamed>' has unknown size
LLVM GCC 4.2 error
expected `;' before 'NSError'
This is the problematic area
#interface FBRequest : NSObject {
#private
id<FBRequestDelegate> _delegate;
NSString* _url;
NSURLConnection* _connection;
NSMutableData* _responseText;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
FBRequestState _state;
#pragma GCC diagnostic pop
NSError* _error;
BOOL _sessionDidExpire;
id<FBGraphObject> _graphObject;
}
XCode 4.5, trying to run in ios 5.1 simulator and ios6 iPod 4. gen
Thanks
try switching to Apple LLVM compiler 4.1 instead of LLVM GCC 4.2 in your Project > Build Settings > Build Options > Compiler for C/C++/Objective-C
p.s. Choose "All" if you don't see "Compiler for C/C++/Objective-C" there.

Resources