Совместимость UIAlertView / UIAlertController iOS 7 и iOS 8
Я использую Swift, чтобы написать приложение, и мне нужно показать предупреждение. Приложение должно быть совместимо с iOS 7 и iOS 8. Так как UIAlertView
был заменен UIAlertController
, Как я могу проверить, если 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)
если я использую UIAlertView для iOS 8, я получаю это предупреждение:Warning: Attempt to dismiss from view controller <_UIAlertShimPresentingViewController: 0x7bf72d60> while a presentation or dismiss is in progress!
14 ответов:
картина обнаружения идентична к типу 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 }
не попробовать и отработать это в зависимости от версии операционной системы. Вам нужно обнаружить способности не ОС.
EDIT
оригинальный детектор для этого ответа
NSClassFromString("UIAlertController")
проваливается под-O
оптимизация, поэтому ее изменили на текущую версия, которая работает на версииEDIT 2
NSClassFromString
работает на всех оптимизациях в Xcode 6.3 / Swift 1.2
для кода, отличного от swift, pure objective-C do this
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]; }
Я был раздражен тем, что мне приходилось выписывать обе ситуации, поэтому я написал совместимый UIAlertController, который работает и для iOS 7, поэтому я просто бросил его на GitHub. Я сделал все возможное, чтобы повторить (гораздо лучше) методы добавления кнопок и действий UIAlertController. Работает как с Objective-C, так и с Swift. Я публикую это, поскольку я нашел этот вопрос при поиске в Google и решил, что это может быть полезно для другие.
вы можете решить вашу проблему с помощью этого кода : -
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
Если это общий код, и есть возможность, что код может быть использован в расширении iOS 8 (где UIAlertView и UIActionSheet являются ограниченными API), а также iOS 7, где UIAlertController не существует, посмотрите на:JVAlertController
Это API-совместимый задний порт UIAlertController для iOS 7, который я взял на себя, чтобы сделать код SDK безопасным для использования как в iOS 7, так и в iOS 8 расширений.
вы можете использовать категорию, чтобы решить эту проблему (хотя вам нужно будет преобразовать ее в 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 )
Если вы используете оба 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]; } ]; ...
Это использует рекомендацию Apple для захвата self в блоке: избегайте сильных опорных циклов при захвате сам
конечно, этот метод предполагает, что у вас есть только один UIAlertView в контроллере и поэтому передайте nil в качестве его значения методу делегата. В противном случае вам нужно будет создать экземпляр (и пометить) "поддельный" UIAlertView для передачи в alertView:didDismissWithButtonIndex.
здесь два пути
UIAlertView
и UIAlertContoller.проверяем 1 : прошивкой версию проверить UIAlertController класса.
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() }
Если вы хотите быть совместимы с iOS 7, просто не используйте
UIAlertController
. Просто.
UIAlertView
не был заменен, он по-прежнему работает отлично и будет продолжать работать отлично в обозримом будущем.
вот мое быстрое решение для перетаскивания:
//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)
остерегайтесь это только для самых основных предупреждений, вам может понадобиться дополнительный код для продвинутых вещей.
попробовать ниже код. Он отлично работает как для iOS 8, так и ниже версии.
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]; }
скачать класс оповещения из этого ссылке и использовать его легко для ios 6, 7 и 8
//Old code **UIAlertView** *alert=[[**UIAlertView** alloc]initWithTitle:@"FreeWare" message:@"Welcome to Common class" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil]; //New code **MyAlertView** *alert=[[**MyAlertView** alloc]initWithTitle:@"FreeWare" message:@"Welcome to Common class" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil];
в iOS8, есть новый класс
UIAlertController
заменяетUIAlertView
иUIActionSheet
. Начиная с iOS8, используйте UIAlertController, а для iOS8 и перед использованием UIAlertView и UIActionSheet. Я думаю, что iOS8 добавилsize classes
что изменилосьUIAlertView
направление дисплея. Смотрите:https://github.com/wangyangcc/FYAlertManage