Совместимость с 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!
Ответы
Ответ 1
Шаблон обнаружения идентичен стилю 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
, поэтому он был изменен на текущую версию, которая работает для версий Release
РЕДАКТИРОВАТЬ 2
NSClassFromString
работает во всех оптимизациях в Xcode 6.3/Swift 1.2
Ответ 2
Для небыстрого кода чистый 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];
}
Ответ 3
Меня раздражало, что мне пришлось записывать обе ситуации, поэтому я написал совместимый UIAlertController, который работает для iOS 7, поэтому я просто бросил его на GitHub. Я сделал все возможное, чтобы воспроизвести (гораздо лучшие) методы добавления кнопок и действий UIAlertController. Работает как с Objective-C, так и с Swift. Я отправляю это, когда нашел этот вопрос при поиске в Google и понял, что это может быть полезно для других.
https://github.com/BayPhillips/compatible-alert-controller
Ответ 4
Вы можете решить свою проблему, используя этот код: -
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
Ответ 5
Swift 2.0
if #available(iOS 8.0, *) {
} else {
}
Ответ 6
Если это общий код и существует вероятность того, что код может использоваться в расширении iOS 8 (где UIAlertView и UIActionSheet являются ограниченными API-интерфейсами), а также iOS 7, где UIAlertController не существует, посмотрите: JVAlertController
Это совместимый с API обратный порт UIAlertController для iOS 7, который я предпринял, чтобы сделать код SDK безопасным для использования в расширениях iOS 7 и iOS 8.
Ответ 7
Вы можете использовать категорию для решения этой проблемы (хотя вам нужно будет преобразовать ее в 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)
Ответ 8
Если вы используете как 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 для захвата себя в блоке: Избегайте сильных ссылочных циклов при самозахвате
Конечно, этот метод предполагает, что у вас есть только один UIAlertView в контроллере и, следовательно, передайте значение nil в качестве значения для метода делегата. В противном случае вам необходимо создать экземпляр (и пометить) "поддельный" UIAlertView для передачи в alertView: didDismissWithButtonIndex.
Ответ 9
Здесь можно проверить два пути UIAlertView
и UIAlertContoller.
Проверить 1: iOS verstion check 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
ноль, а затем версию 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()
}
Ответ 10
Если вы хотите быть совместимым с iOS 7, просто не используйте UIAlertController
. Просто как это.
UIAlertView
не был заменен, он по-прежнему отлично работает и будет работать отлично в обозримом будущем.
Ответ 11
Вот мое быстрое и быстрое решение:
//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)
Помните, что это только для самых основных предупреждений, вам может понадобиться дополнительный код для продвинутых материалов.
Ответ 12
Попробуйте ввести код ниже. Он отлично работает для 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];
}
Ответ 13
В iOS8 существует новый класс UIAlertController
, который заменяет UIAlertView
и UIActionSheet
. Начиная с iOS8, используйте UIAlertController и для iOS8 и перед использованием UIAlertView и UIActionSheet. Я думаю, что iOS8 добавил size classes
, которые меняют направление отображения UIAlertView
. См.: https://github.com/wangyangcc/FYAlertManage
Ответ 14
загрузить класс предупреждения из этой
и использовать его легко для 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];