HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Generic class for displaying UIAlertView / UIAlertController on iOS

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
genericuialertviewiosdisplayingforclassuialertcontroller

Problem

To address backwards compatibility for UIAlertView, I have come up with an interface that would seem to work for both iOS versions 8 and lower.

This is not something I would like to roll out in production hence I would appreciate few extra pair of eyes taking a look at it.

Here is a link to the GitHub gist.

```
//UIAlertMode.h
#import
#import

typedef void (^AlertViewSelectionBlock) (NSInteger);
typedef void (^AlertControllerDefaultAction ) (UIAlertAction *);
typedef void (^AlertControllerCancelAction) (UIAlertAction *);
typedef void (^GenericBlock) (void *);

@interface UIAlertMode : NSObject

@property (assign, nonatomic) AlertViewSelectionBlock alertViewBlock;
@property (assign, nonatomic) AlertControllerCancelAction cancelAlertAction;
@property (assign, nonatomic) AlertControllerDefaultAction defaultAlertAction;

  • (id) initAlertWith:(NSString *) title


:(NSString *) message
:(NSString *) cancelButtonTitle
:(NSString *) otherButtonTitle;

  • (BOOL) supportsiOS8;
  • (void) showAlertFor:(AlertViewSelectionBlock) alertViewBlock;
  • (void) showAlertControllerFor:(AlertControllerDefaultAction) defaultAction :(AlertControllerCancelAction) cancelAction;
  • (void) showAlertWith:(GenericBlock) block;


@end

// UIAlertMode.m

#import "UIAlertMode.h"
#import
#import "AppDelegate.h"

@interface UIAlertMode () {
UIAlertView *_alertView;
UIAlertController *_alertController;
}

@end

@implementation UIAlertMode

@synthesize alertViewBlock;
@synthesize defaultAlertAction;
@synthesize cancelAlertAction;

  • (id) init {


self = [super init];
return self;
}

  • (id) initAlertWith:(NSString *) title


:(NSString *) message
:(NSString *) cancelButtonTitle
:(NSString *) otherButtonTitle {
self = [super init];
if ([self supportsiOS8]) {
_alertController = [UIAlertController alertControllerWithTitle:title message:message preferred

Solution

As a start, this is confusing:

- (BOOL) supportsiOS8 {
    Class kAlertViewClass = NSClassFromString(@"UIAlertController");
    return !kAlertViewClass ? NO : YES;
}


There was a time when I was uncomfortable with ternary operators. They're admittedly kind of weird. I've gotten used to them, and I do enjoy them, but they should be used appropriately.

The logic here is that NSClassFromString returns nil if it can't figure out what class you've specified.

For starters, I'd change this to look more like this:

- (BOOL)supportsiOS8 {
    return NSClassFromString(@"UIAlertController") != nil;
}


Now it's slightly more readable and more clear what we're doing. We don't actually care what's returned beyond whether or not it is nil.

However, there's still problems...

Your method is called supportsiOS8, but all your method actually checks is whether or not this class can see a class called UIAlertController. And there's a difference.

I can use a class called UIAlertController on iOS 7 and lower. It's simply a matter of me implementing that class myself. If I've imported that class's file into this file, your supportsiOS8 will return YES. And my implementation of UIAlertController may or may not match Apple's implementation. So with that said, simply renaming the method as supportsAlertController wouldn't really work.

Moreover, it's likely that UIAlertController will continue to exist in iOS 9 and onward. Apps that use this class may or may not actually support iOS 8 (because supporting iOS 8 isn't actually necessary).

Instead, what we actually need to do is check the version of iOS that the user is actually using and compare it to the minimum iOS version for Apple's UIAlertController (iOS 8).

For starters, we can use the following method to determine the device's version:

[[UIDevice currentDevice] systemVersion];


This will return the device's version as an NSString. It might look something like @"8.1".

Now, we compare the return of this to the version we want.

- (BOOL)hasMinimumRequiredOS {
    NSString *deviceVersion = [[UIDevice currentDevice] systemVersion];
    return ([deviceVersion compare:@"8" options:NSNumericSearch] != NSOrderedAscending);
}

Code Snippets

- (BOOL) supportsiOS8 {
    Class kAlertViewClass = NSClassFromString(@"UIAlertController");
    return !kAlertViewClass ? NO : YES;
}
- (BOOL)supportsiOS8 {
    return NSClassFromString(@"UIAlertController") != nil;
}
[[UIDevice currentDevice] systemVersion];
- (BOOL)hasMinimumRequiredOS {
    NSString *deviceVersion = [[UIDevice currentDevice] systemVersion];
    return ([deviceVersion compare:@"8" options:NSNumericSearch] != NSOrderedAscending);
}

Context

StackExchange Code Review Q#67378, answer score: 3

Revisions (0)

No revisions yet.