web-dev-qa-db-ja.com

UIAlertView / UIAlertController iOS 7およびiOS 8の互換性

アプリの作成にSwiftを使用していますが、アラートを表示する必要があります。アプリはiOS 7およびiOS 8互換である必要があります。 UIAlertViewUIAlertControllerに置き換えられているので、システムバージョンを確認せずにUIAlertControllerが利用可能かどうかを確認するにはどうすればよいですか? Appleは、APIの可用性を判断するためにデバイスのシステムバージョンを確認しないことを推奨していると聞いています。

これは私がiOS 8で使用しているものですが、これはiOS 7で「dyld: Symbol not found: _OBJC_CLASS_$_UIAlertAction」でクラッシュします:

let alert = UIAlertController(title: "Error", message: message, preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alert.addAction(cancelAction)
presentViewController(alert, animated: true, completion: nil)

IOS 8のUIAlertViewを使用すると、次の警告が表示されます:Warning: Attempt to dismiss from view controller <_UIAlertShimPresentingViewController: 0x7bf72d60> while a presentation or dismiss is in progress!

57
Shan

検出パターンはObjective-Cスタイルと同じです。

現在アクティブなランタイムにこのクラスをインスタンス化する機能があるかどうかを検出する必要があります

if objc_getClass("UIAlertController") != nil {

     println("UIAlertController can be instantiated")

      //make and use a UIAlertController

 }
 else {

      println("UIAlertController can NOT be instantiated")

      //make and use a UIAlertView
}

OSのバージョンに基づいてこれを試そうとしないでください。能力を検出する必要がありますNOT OS。

編集

この回答の元の検出器NSClassFromString("UIAlertController")-O最適化で失敗するため、リリースビルドで機能する現在のバージョンに変更されました

編集2

NSClassFromStringはXcode 6.3/Swift 1.2のすべての最適化で機能しています

76
Warren Burton

非Swiftコードの場合、純粋なobjective-Cがこれを行います

if ([UIAlertController class])
    {
        // use UIAlertController
        UIAlertController *alert= [UIAlertController
                                      alertControllerWithTitle:@"Enter Folder Name"
                                      message:@"Keep it short and sweet"
                                      preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction* ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                                   handler:^(UIAlertAction * action){
                                                       //Do Some action here
                                                       UITextField *textField = alert.textFields[0];
                                                       NSLog(@"text was %@", textField.text);

                                                   }];
        UIAlertAction* cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleDefault
                                                       handler:^(UIAlertAction * action) {

                                                           NSLog(@"cancel btn");

                                                           [alert dismissViewControllerAnimated:YES completion:nil];

                                                       }];

        [alert addAction:ok];
        [alert addAction:cancel];

        [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
            textField.placeholder = @"folder name";
            textField.keyboardType = UIKeyboardTypeDefault;
        }];

        [self presentViewController:alert animated:YES completion:nil];

    }
    else
    {
        // use UIAlertView
        UIAlertView* dialog = [[UIAlertView alloc] initWithTitle:@"Enter Folder Name"
                                                         message:@"Keep it short and sweet"
                                                        delegate:self
                                               cancelButtonTitle:@"Cancel"
                                               otherButtonTitles:@"OK", nil];

        dialog.alertViewStyle = UIAlertViewStylePlainTextInput;
        dialog.tag = 400;
        [dialog show];

    }
29
Sam B

私は両方の状況を書き続けなければならないことに悩まされていたので、iOS 7でも動作する互換性のあるUIAlertControllerを書いたので、GitHubに投げました。 UIAlertControllerのボタンとアクションを追加する(はるかに優れた)メソッドを複製するために最善を尽くしました。 Objective-CとSwiftの両方で動作します。 Googleで検索するときにこの質問を見つけ、他の人に役立つ可能性があると考えたため、これを投稿しています。

https://github.com/BayPhillips/compatible-alert-controller

9
Bay Phillips

このコードを使用して問題を解決できます:-

var device : UIDevice = UIDevice.currentDevice()!;
        var systemVersion = device.systemVersion;
        var iosVerion : Float = systemVersion.bridgeToObjectiveC().floatValue;
        if(iosVerion < 8.0) {
            let alert = UIAlertView()
            alert.title = "Noop"
            alert.message = "Nothing to verify"
            alert.addButtonWithTitle("Click")
            alert.show()
        }else{
            var alert : UIAlertController = UIAlertController(title: "Noop", message: "Nothing to verify", preferredStyle: UIAlertControllerStyle.Alert)
            alert.addAction(UIAlertAction(title: "Click", style:.Default, handler: nil))
            self.presentViewController(alert, animated: true, completion: nil)
        }

uIKitは必須ではなくオプションとしてマークする必要がありました。

Courtsey:- iOS 7およびiOS 8で動作可能なアラート

8
Shivaay

Swift 2.0

 if #available(iOS 8.0, *) {

 } else {

 }
6
William Hu

これが共有コードであり、コードがiOS 8拡張機能(UIAlertViewとUIActionSheetが制限されたAPI)およびUIAlertControllerが存在しないiOS 7で使用できる可能性がある場合は、以下を参照してください- JVAlertController

これは、iOS 7とiOS 8の両方の拡張機能でSDKコードを安全に使用できるようにするために、iOS 7に対するUIAlertControllerのAPI互換のバックポートです。

4
jverdi

カテゴリを使用してそれを解決できます(ただし、Swiftに変換する必要があります)。

@implementation UIView( AlertCompatibility )

+( void )showSimpleAlertWithTitle:( NSString * )title
                          message:( NSString * )message
                cancelButtonTitle:( NSString * )cancelButtonTitle
{
    if( [[UIDevice currentDevice] isSystemVersionLowerThan: @"8"] )
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle: title
                                                        message: message
                                                       delegate: nil
                                              cancelButtonTitle: cancelButtonTitle
                                              otherButtonTitles: nil];
        [alert show];
    }
    else
    {
        // nil titles break alert interface on iOS 8.0, so we'll be using empty strings
        UIAlertController *alert = [UIAlertController alertControllerWithTitle: title == nil ? @"": title
                                                                       message: message
                                                                preferredStyle: UIAlertControllerStyleAlert];

        UIAlertAction *defaultAction = [UIAlertAction actionWithTitle: cancelButtonTitle
                                                                style: UIAlertActionStyleDefault
                                                              handler: nil];

        [alert addAction: defaultAction];

        UIViewController *rootViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
        [rootViewController presentViewController: alert animated: YES completion: nil];
    }
}

@end

@implementation UIDevice( SystemVersion )

-( BOOL )isSystemVersionLowerThan:( NSString * )versionToCompareWith
{
    if( versionToCompareWith.length == 0 )
        return NO;

    NSString *deviceSystemVersion = [self systemVersion];
    NSArray *systemVersionComponents = [deviceSystemVersion componentsSeparatedByString: @"."];

    uint16_t deviceMajor = 0;
    uint16_t deviceMinor = 0;
    uint16_t deviceBugfix = 0;

    NSUInteger nDeviceComponents = systemVersionComponents.count;
    if( nDeviceComponents > 0 )
        deviceMajor = [( NSString * )systemVersionComponents[0] intValue];
    if( nDeviceComponents > 1 )
        deviceMinor = [( NSString * )systemVersionComponents[1] intValue];
    if( nDeviceComponents > 2 )
        deviceBugfix = [( NSString * )systemVersionComponents[2] intValue];


    NSArray *versionToCompareWithComponents = [versionToCompareWith componentsSeparatedByString: @"."];

    uint16_t versionToCompareWithMajor = 0;
    uint16_t versionToCompareWithMinor = 0;
    uint16_t versionToCompareWithBugfix = 0;

    NSUInteger nVersionToCompareWithComponents = versionToCompareWithComponents.count;
    if( nVersionToCompareWithComponents > 0 )
        versionToCompareWithMajor = [( NSString * )versionToCompareWithComponents[0] intValue];
    if( nVersionToCompareWithComponents > 1 )
        versionToCompareWithMinor = [( NSString * )versionToCompareWithComponents[1] intValue];
    if( nVersionToCompareWithComponents > 2 )
        versionToCompareWithBugfix = [( NSString * )versionToCompareWithComponents[2] intValue];

    return ( deviceMajor < versionToCompareWithMajor )
           || (( deviceMajor == versionToCompareWithMajor ) && ( deviceMinor < versionToCompareWithMinor ))
           || (( deviceMajor == versionToCompareWithMajor ) && ( deviceMinor == versionToCompareWithMinor ) && ( deviceBugfix < versionToCompareWithBugfix ));
}

@end

それからちょうど電話

[UIView showSimpleAlertWithTitle: @"Error" message: message cancelButtonTitle: @"OK"];

ただし、システムバージョンを確認したくない場合は、

BOOL lowerThaniOS8 = NSClassFromString( @"UIAlertController" ) == nil;

カテゴリUIView(AlertCompatibility)内

2
Daniel Alves

上記のようにiOS 7- UIAlertViewとiOS 8+ UIAlertControllerの両方を使用し、UIAlertControllerブロックがUIAlertViewのデリゲート(MyControllerなど)alertView:didDismissWithButtonIndexメソッドを呼び出して結果の処理を続行する場合は、次の方法の例を示します。それ:

if ([UIAlertController class]) {
    MyController * __weak mySelf = self;

    UIAlertController *alertController = [UIAlertController
        alertControllerWithTitle:alertTitle
        message:alertMessage
        preferredStyle:UIAlertControllerStyleAlert];

    UIAlertAction *cancelAction = [UIAlertAction
        actionWithTitle:alertCancel
        style:UIAlertActionStyleCancel
        handler:^(UIAlertAction *action)
            {
            [mySelf alertView:nil didDismissWithButtonIndex:0];
            }
    ];

...

これは、ブロックのselfをキャプチャするためのAppleの推奨事項を使用します: self

もちろん、このメソッドは、コントローラーにUIAlertViewが1つしかないため、nilをデリゲートメソッドに値として渡すことを前提としています。それ以外の場合は、alertView:didDismissWithButtonIndexに渡すために「偽の」UIAlertViewをインスタンス化(およびタグ付け)する必要があります。

2
ScottyB

ここでUIAlertViewIAlertContoller の2つの方法を確認します。

チェック1:iOSバージョンチェック IAlertController クラス。

    if #available(iOS 8.0, *) {

        // UIALertController
        let alert = UIAlertController(title: "Alert", message: "Alert after 8.0", preferredStyle: .Alert)
        let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
        alert.addAction(cancelAction)
        presentViewController(alert, animated: true, completion: nil)
    } else {

        // UIALertView
        UIAlertView(title: "Alert", message: "Alert below iOS V 8.0", delegate: nil, cancelButtonTitle: "OK").show()
    }

チェック2:チェックUIAlertController nilその後、iOSバージョン8.0以下。

    if objc_getClass("UIAlertController") != nil {

        // UIALertController
        let alert = UIAlertController(title: "Alert", message: "Alert after 8.0", preferredStyle: .Alert)
        let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
        alert.addAction(cancelAction)
        presentViewController(alert, animated: true, completion: nil)

    }
    else {

        // UIALertView
        UIAlertView(title: "Alert", message: "Alert below iOS V 8.0", delegate: nil, cancelButtonTitle: "OK").show()
    }
1
Kirit Modi

IOS 7との互換性が必要な場合は、UIAlertControllerを使用しないでください。そのような単純な。

UIAlertViewは置き換えられていませんが、引き続き完全に機能し、近い将来、完全に機能し続けます。

0
Abhi Beckert

これが私のドラッグアンドドロップSwiftソリューションです。

//Alerts change in iOS8, this method is to cover iOS7 devices
func CozAlert(title: String, message: String, action: String, sender: UIViewController){

    if respondsToSelector("UIAlertController"){
        var alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: action, style: UIAlertActionStyle.Default, handler:nil))
        sender.presentViewController(alert, animated: true, completion: nil)
    }
    else {
        var alert = UIAlertView(title: title, message: message, delegate: sender, cancelButtonTitle:action)
        alert.show()
    }
}

このような呼び出し:

CozAlert("reportTitle", message: "reportText", action: "reportButton", sender: self)

これは最も基本的なアラート専用であり、高度なものには追加のコードが必要になる場合があることに注意してください。

0
Esqarrouth