NS_CLASS_AVAILABLE not working - ios

I'm trying to use NS_CLASS_AVAILABLE (NS_CLASS_AVAILABLE_IOS to be precise) in a project but it seems it doesn't work.
I have tried:
NS_CLASS_AVAILABLE_IOS(7_0) #interface Dummy : NSObject
#end
Then when I have tried to check if the class is available:
if ([Dummy class]) {
NSLog(#"Dummy available");
} else {
NSLog(#"Dummy not available");
}
I always get "Dummy available", even in the iOS 6 simulator.
To check I have tried with NSURLSession:
if ([NSURLSession class]) {
NSLog(#"NSURLSession available");
} else {
NSLog(#"NSURLSession not available");
}
And, this time, I correctly get "NSURLSession not available".
Is there something I'm doing wrong?
Is there a compiler flag or something?

Related

Comparing class is giving incorrect output

I am using below code to check view controllers.
NSLog(#"addProductClicked 1===%#", self.class);
NSLog(#"addProductClicked 2===%#", [CategoriesViewController class]);
if ([self.class isKindOfClass:[CategoriesViewController class]]) {
NSLog(#"you go it right");
} else {
NSLog(#"you go it wrong");
}
The output I get is as below.
addProductClicked 1===CategoriesViewController
addProductClicked 2===CategoriesViewController
you go it wrong
Any idea what is going wrong?
Just to update, below is what I have defined my view controller...
#interface CategoriesViewController : GlobalViewController {
Now in GlobalViewController I have method where I am checking above...
The variable you want to class check should be passed in as an object, not as a class.
if ([self isKindOfClass:[CategoriesViewController class]]) {
NSLog(#"you go it right");
} else {
NSLog(#"you go it wrong");
}
Thats is wrong comparison. You call isKindOfClass: on the object of that class. Something like this:
CategoriesViewController *obj = [[CategoriesViewController alloc] init];
[obj isKindOfClass:CategoriesViewController];
In your case you probably want to put a check on self.

No visible #interface for 'JSQSystemSoundPlayer' declares the selector 'playSoundWithFilename:fileExtension:'

This is where my build fails in JSQSystemSoundPlayer. I cannot get around this.
if (asAlert) {
[[JSQSystemSoundPlayer sharedPlayer] playAlertSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF];
}
else {
[[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF];
}
According to the header file, I think you need to include a completion block (which you can set to nil if you don't want anything doing).
if (asAlert) {
[[JSQSystemSoundPlayer sharedPlayer] playAlertSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF completion:nil];
} else {
[[JSQSystemSoundPlayer sharedPlayer] playSoundWithFilename:fileName fileExtension:kJSQSystemSoundTypeAIFF completion:nil];
}

UIAlertController if iOS 8, otherwise UIAlertView

I want to conform to the UIAlertController used in iOS 8 since UIAlertView is now deprecated. Is there a way that I can use this without breaking support for iOS 7? Is there some kind of if condition I can do to check for iOS 8 otherwise do something else for iOS 7 support?
I think a much better way to check if a class exists (since iOS 4.2) is:
if([ClassToBeChecked class]) {
// use it
} else {
// use alternative
}
In your case, that would be:
if ([UIAlertController class]) {
// use UIAlertController
} else {
// use UIAlertView
}
Objective C (as mentioned above)
if ([UIAlertController class]) {
// use UIAlertController
} else {
// use UIAlertView
}
Swift
if objc_getClass("UIAlertController") == nil {
// use UIAlertView
} else {
// use UIAlertController
}
Don't use if NSClassFromString("UIAlertController") == nil It is not working because the signature for this method is func NSClassFromString(_ aClassName: String!) -> AnyClass!
Please see the answer of Erwan (below my answer) as I see it is the best.
--
You can check the iOS version to use appropriate control like this:
if (([[[UIDevice currentDevice] systemVersion] compare:#"8.0" options:NSNumericSearch] == NSOrderedAscending)) {
// use UIAlertView
}
else {
// use UIAlertController
}
As others have already mentioned - always check whether a feature exists. I believe the safest approach is following:
if (NSClassFromString(#"UIAlertController")) {
// use UIAlertController
} else {
// use UIAlertView
}
With the obvious risk of entering a class name with a typo. :)
From documentation of NClassFromString:
[Returns] The class object named by aClassName, or nil if no class by that name is currently loaded. If aClassName is nil, returns nil.
Availability iOS (2.0 and later)
Solution for checking iOS version in Swift
switch (UIDevice.currentDevice().systemVersion.compare("8.0.0", options: NSStringCompareOptions.NumericSearch)) {
case .OrderedAscending:
println("iOS < 8.0")
case .OrderedSame, .OrderedDescending:
println("iOS >= 8.0")
}
Con of this solution: it is simply bad practice to check against OS version numbers, whichever way you do it. One should never hard code dependencies in this way, always check for features, capabilities or the existence of a class. Consider this; Apple may release a backwards compatible version of a class, if they did then the code you suggest would never use it as your logic looks for an OS version number and NOT the existence of the class.
(Source of this information)
Solution for checking the class' existence in Swift
if (objc_getClass("UIAlertController") == nil) {
// iOS 7
} else {
// iOS 8+
}
Do not use if (NSClassFromString("UIAlertController") == nil) because it works correctly on the iOS simulator using iOS 7.1 and 8.2, but if you test on a real device using iOS 7.1, you will unfortunately notice that you will never pass through the else part of the code snippet.
// Above ios 8.0
float os_version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (os_version >= 8.000000)
{
   //Use UIAlertController
}
else
{
//UIAlertView
}
Create simple utility function to reduce code
CODE :
// pass minimum required iOS version
BOOL isOSSupported(NSString *minRequiredVersion)
{
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
BOOL isOSSupported = ([currSysVer compare:minRequiredVersion options:NSNumericSearch] != NSOrderedAscending) &&
![currSysVer isEqualToString:#"Unknown"];
return isOSSupported;
}
USE :
if(isOSSupported("8.0")
{
// Code for iOS8 and above
}
else
{
// Code for iOS7 and below
}
Or Use system constant NSFoundationVersionNumber_iOS_7_1 as below
if(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
{
// Code for iOS8 and above
}
else
{
// Code for iOS7 and below
}
for more options Link
I have created very simple wrapper in Objective-C, that supports both - old iOS UIAlertView and new one UIAlertViewController
https://github.com/MartinPerry/UIAlert/
It also brings the new action blocks usage to old UIAlertView
Sample:
MyAlertMessage * a = [[MyAlertMessage alloc] initWithTitle:#"Hello" WithMessage:#"World"];
[a addButton:BUTTON_OK WithTitle:#"OK" WithAction:^(void *action) {
NSLog(#"Button OK at index 0 click");
}];
[a addButton:BUTTON_CANCEL WithTitle:#"Cancel" WithAction:^(void *action) {
NSLog(#"Button Cancel at index 1 click");
}];
[a show];
I have written one class that wrap the UIAlertView and use UIAlertController. For the programmer is transparently hence is sufficient import this classes in the project. The utility of this classes is when in a old project there are more UIAlertView to change. Link: https://github.com/kennymuse/UIAlertView
Method one
by ios system version check
#define iOSVersionLessThan(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
// below ios8 ,create UIAlertView
if(iOSVersionLessThan(#"7.0")){
// todo
// ios8 and above ,UIActionController avaliable
}else{
// todo
}
Method two
by system feature detect
// create UIActionController
if([UIActionController class]){
// todo
// create UIAlertView
}else{
// todo
}
But,there's a third lib named PSTAlertController that deal with backwards compatible to iOS 7 of UIActionSheet and UIAlertView.
ref to
Supporting Multiple Versions of iOS
Supporting iOS 6
Supporting Multiple iOS Versions and Devices
Try below code. It works fine for both iOS 8 and below version.
if (IS_OS_8_OR_LATER) {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction
actionWithTitle:#"OK"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *action)
{
}];
[alertVC addAction:cancelAction];
[[[[[UIApplication sharedApplication] windows] objectAtIndex:0] rootViewController] presentViewController:alertVC animated:YES completion:^{
}];
}
else{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}

How to dynamically lock the orientation of the ios Native app

I am new to Objective c Native coding in IOS. I am having two buttons. One to lock the app to portrait and another lock the landscape orientation. What should I do to achieve this. Locking in the sense it will fix to the locked side and will not turn.
Yes i have used a method to implement the same using ios plugin which i created in worklight(For hybrid apps).
The function for setting the flag is
#import "HelloworlPlugin.h"
#implementation HelloworlPlugin
int count=0;
-(void)sayhello:(NSMutableArray *)arguments withDict:(NSMutableDictionary *)option
{
[arguments pop];
NSString *responseString=[NSString stringWithFormat:#"%#",[arguments objectAtIndex:0]];
if([responseString isEqualToString:#"1"])
{
count=1;
}
else
{
count=0;
}
NSLog(#"Zero %#",responseString);
}
-(int)count1
{
NSLog(#"count= %d",count);
if(count<1)
{
Cv=0;
}
else
{
Cv=1;
}
NSLog(#"%d",Cv);
return Cv;
}
#end
Where in say hello function i get the arguments from the hybrid app and based on that i set the flag variable Cv to 1 or 0.
Below is the default method which i have changed little bit to do my implementation
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
HelloworlPlugin *object=[[HelloworlPlugin alloc] init];
int fValue=[object count1];
NSLog(#"%d",fValue);
if(fValue==1)
{
return (interfaceOrientation ==UIInterfaceOrientationPortrait);
}
else
{
return true;
}
}
shouldAutorotateToInterfaceOrientation
is a thing that is default function based on which the orientation is set returning true set all the orientation else by giving the approriate orientation we can set the answer.So here based on the cv value i stored in fValue i have locked the orientation.
For example this way:
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];

Delegate and Protocol code not entering delegate method

I am working on an user activation errors, I have a NSObject class that gets call if an error is returned from the DB.
I show an alertview that has a method called when the user presses the UIButton on the alert view. This is what the method looks like.
//ErrorHandling.m
//
case 1: {
NSLog(#"ERROR = 1");
message = [[UIAlertView alloc] initWithTitle:#"Error 1:"
message:#"The activation request failed."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
message.tag = myAlertViewsTag;
[self performSelector:#selector(showAlertViewAndMessage) withObject:message afterDelay:0.3]; // set timer to give any huds time to load so I can unload them correctly
}
break;
//
- (void)showAlertViewAndMessage {
[SVProgressHUD dismiss];
[message show];
}
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (alertView.tag == myAlertViewsTag) {
if (buttonIndex == 0) {
if (receivedResponseData != nil) {
if (errorCodeValue == 1) {
[[self errorDataDelegate] passErrorDataToRoot:receivedResponseData];
}
// incase the user is further on in the navigationstack bring them back to the rootview
[self.currentNavigationController popToRootViewControllerAnimated:YES];
}
}
}
so far all this code works, accept for the delegate/protocol request... I have checked and double checked my code, however I think maybe I am missing something that maybe you can see. This is what my Delegate and Protocol looks like.
//errorHandling.h
#protocol RecivedErrorData <NSObject>
- (void)passErrorDataToRoot:(NSData *)errorData;
#end
//Protocol/delegate
__weak id <RecivedErrorData> errorDataDelegate;
//Protocol/delegate
#property (weak, nonatomic) id <RecivedErrorData> errorDataDelegate;
//errorHandling.m
//delegate / protocols
#synthesize errorDataDelegate;
[[self errorDataDelegate] passErrorDataToRoot:receivedResponseData];
//RootViewController.h
#import "ErrorHandling.h"
#interface RootViewController : UIViewController <RecivedErrorData> {
// error handling for activations
ErrorHandling *errorHandling;
//RootViewController.m
-(void)viewDidLoad {
errorHandling = [[ErrorHandling alloc] init];
[errorHandling setErrorDataDelegate:self];
}
#pragma ErrorProtocol
- (void)passErrorDataToRoot:(NSData *)errorData {
NSLog(#"WORKED");
}
So thats my code for the protocol and delegate, it almost works when the button is clicked it just never maked it to passErrorDataToRoot delegate method.
I am wondering if its an error in initialization, ErrorHandling.h is initialized originally when the app starts up inside the rootView, then when I get an error from a request I call ErrorHandling.m from a class called EngineRequest.m using alloc init etc... that's the only thing I can think of, that because of this extra allocation im dealing with another method but I am not sure this is the reason? I thought delegates and protocols were used to avoid this issue of reallocation.

Resources