UIAlertController, если iOS 8, иначе UIAlertView

Я хочу соответствовать UIAlertController, используемому в iOS 8, поскольку UIAlertView теперь устарел. Есть ли способ, которым я могу использовать это, не нарушая поддержку iOS 7? Есть ли какое-то условие, которое я могу выполнить, чтобы проверить iOS 8, иначе сделать что-то еще для поддержки iOS 7?


person Rocky Pulley    schedule 17.06.2014    source источник
comment
К вашему сведению. Поскольку вашей целью развертывания является iOS 7 (или более ранняя версия), вы можете просто использовать UIAlertView. Это сделает ваш код намного проще.   -  person rmaddy    schedule 17.06.2014
comment
Я не знал, что у Swift есть responsesToSelector... Кроме того, UIAlertView облажался в ios8, он не прокручивается, как в ios 7, поэтому я хочу попробовать использовать оба   -  person Rocky Pulley    schedule 17.06.2014
comment
Прокрутка также не работает на UIAlertController.   -  person jcesarmobile    schedule 24.09.2014
comment
возможный дубликат UIAlertView/UIAlertController iOS 7 и совместимость с iOS 8   -  person JAL    schedule 25.06.2015


Ответы (10)


См. ответ Эрвана (под моим ответом), поскольку я вижу, что он лучший.

--

Вы можете проверить версию iOS, чтобы использовать соответствующий элемент управления, например:

if (([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] == NSOrderedAscending)) {
    // use UIAlertView
}
else {
    // use UIAlertController
}
person Tristian    schedule 30.06.2014
comment
Ниже я разместил то, что считаю лучшим подходом, проверяя, существует ли класс, а не проверяя версию ОС. - person Erwan; 04.09.2014
comment
Это хрупкий способ выполнить эту проверку. На самом деле Apple не рекомендует такие проверки. Ответ Эрвана - правильный ответ. - person squarefrog; 07.10.2014
comment
Никогда не следует проверять номера версий в коде, это очень плохая практика. Как указывает Squarefrog, у @Erwan есть лучшее решение, всегда проверяйте возможности/функции. - person SHaKie; 15.10.2014
comment
Как уже отмечалось, условная оценка [класса UIAlertController] является предпочтительной стратегией. Если необходима проверка версии для ОС, рекомендуется сравнить NSFoundationVersionNumber -- подробно здесь - person Mark; 09.02.2015

Я думаю, что гораздо лучший способ проверить, существует ли класс (начиная с iOS 4.2):

if([ClassToBeChecked class]) {

   // use it

} else {

  // use alternative

}

В вашем случае это будет:

if ([UIAlertController class]) {
   // use UIAlertController

} else {
  // use UIAlertView

}
person Erwan    schedule 04.09.2014
comment
Я пытался это сделать, но когда я запускаю XCode 5, мой код не компилируется. Как мне убедиться, что это действительно работает на iOS7? - person Huey; 08.10.2014
comment
Это определенно должно работать на iOS7 и Xcode5. Не стесняйтесь размещать свой код здесь. Что-то должно быть не так - person Erwan; 16.10.2014
comment
Это должно быть отмечено как правильный ответ. Всегда проверяйте наличие класса/функции/константы/функции вместо проверки версии iOS. - person Vilém Kurz; 22.10.2014
comment
Спасибо @VilémKurz, но как пометить ответ как правильный? - person Erwan; 22.10.2014
comment
это может зависеть от того, есть ли у вас ios 8 SDK. stackoverflow.com/questions/24015490/ - person mitrenegade; 24.10.2014
comment
Как это сделать на Свифте? - person ChikabuZ; 26.11.2014
comment
@mitrenegade такой подход не позволяет вам проверить версию iOS. Он будет работать на любой iOS после 4.2 - person Erwan; 27.11.2014
comment
Да, но если кто-то компилирует код, написанный кем-то с ios 8 sdk, но теперь использует ios 7 sdk на xcode 5, код не скомпилируется. Это проблема, с которой сталкивается @huey, потому что он компилирует xcode 5, UIAlertController не будет распознан. Если вы используете самую последнюю версию SDK, ваш ответ будет правильным, потому что когда телефон под управлением ios7 запускает ваше приложение, созданное с помощью ios8, оно просто возвращает nil в [класс UIAlertController]. - person mitrenegade; 27.11.2014
comment
@mitrenegade, но если он компилирует iOS7 на Xcode 5, остальная часть кода все равно не скомпилируется. Какой смысл тестировать, если версия позволяет использовать этот класс, если вы компилируете его с версией, которая не знает класс - person Erwan; 27.11.2014
comment
правильно, поэтому @huey не должен пытаться компилировать на xcode 5. ему нужно использовать xcode 6 и использовать ваш код, чтобы предотвратить вызов UIAlertController, если устройство использует ios7. мой комментарий должен был указать, что причина, по которой он не компилируется, заключается в том, что класс недоступен в ios 7 sdk. однако в вашем первом ответе говорилось, что он будет работать на ios7 и xcode 5, что неверно, если этот класс недоступен. - person mitrenegade; 27.11.2014
comment
@huey может использовать Xcode 6 для сборки и запуска на симуляторе iOS7, чтобы убедиться, что его код работает на iOS7. Для этого ему не нужен Xcode5. - person Erwan; 28.11.2014
comment
Моя практика заключается в том, чтобы обращаться к библиотеке разработчиков и кодировать соответственно. Например, UIActionSheet устарел в пользу UIAlertController в iOS 8, но [класс UIActionSheet] вернет true в iOS 8. Если вы сомневаетесь, прочитайте библиотеку, чтобы проконсультироваться с API, и проверьте версию ОС и существование класса в код для лучшей практики (защитное программирование). - person Hahnemann; 13.06.2015

Задача C (как указано выше)

if ([UIAlertController class]) {
    // use UIAlertController

} else {
    // use UIAlertView

}

Быстрый

if objc_getClass("UIAlertController") == nil  {
       // use UIAlertView 

} else {
  // use UIAlertController

}

Не используйте if NSClassFromString("UIAlertController") == nil. Он не работает, потому что сигнатура для этого метода func NSClassFromString(_ aClassName: String!) -> AnyClass!.

person goce    schedule 19.01.2015

Как уже упоминалось, всегда проверяйте, существует ли функция. Я считаю, что самый безопасный подход следующий:

if (NSClassFromString(@"UIAlertController")) {
    // use UIAlertController
} else {
    // use UIAlertView
}

С очевидным риском ввода имени класса с опечаткой. :)

Из документации NClassFromString:

[Возвращает] Объект класса с именем aClassName или nil, если класс с таким именем в настоящее время не загружен. Если aClassName равно nil, возвращает nil.

Доступность iOS (2.0 и выше)

person xius    schedule 23.10.2014
comment
Этот фрагмент кода, переведенный на Swift, правильно работает на симуляторе iOS с использованием iOS 7.1 и 8.2, но если вы протестируете его на реальном устройстве с iOS 7.1, вы, к сожалению, заметите, что никогда не пройдете через else часть фрагмента кода. Так что этот фрагмент кода нестабилен, и я бы не рекомендовал его использовать в продакшене. - person King-Wizard; 17.03.2015
comment
Комментарий alino-91 верен. Вместо этого используйте objc_getClass - person grandagile; 18.05.2015

Решение для проверки версии iOS в 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")
}

Минус этого решения: просто плохая практика сверяться с номерами версий ОС, как бы вы это ни делали. Никогда не следует жестко кодировать зависимости таким образом, всегда проверяйте функции, возможности или существование класса. Учти это; Apple может выпустить обратно совместимую версию класса, если они это сделают, то предлагаемый вами код никогда не будет использовать его, поскольку ваша логика ищет номер версии ОС, а НЕ существование класса.

(Источник этой информации)

Решение для проверки существования класса в Swift

if (objc_getClass("UIAlertController") == nil) {
   // iOS 7
} else {
   // iOS 8+
}

Не используйте if (NSClassFromString("UIAlertController") == nil), потому что он корректно работает на симуляторе iOS с использованием iOS 7.1 и 8.2, но если вы протестируете на реальном устройстве с iOS 7.1, вы, к сожалению, заметите, что никогда не пройдете через else часть фрагмента кода.

person King-Wizard    schedule 18.03.2015
comment
Не используйте if (NSClassFromString(UIAlertController) == nil), потому что он правильно работает на симуляторе iOS с использованием iOS 7.1 и 8.2, но если вы протестируете на реальном устройстве с iOS 7.1, вы, к сожалению, заметите, что никогда не пройдете через еще часть фрагмента кода. Это правда. Хотел бы я прочитать это раньше. - person grandagile; 18.05.2015

Создайте простой utility function, чтобы сократить объем кода

КОД:

// 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;
}


ИСПОЛЬЗОВАНИЕ:

if(isOSSupported("8.0")
{
// Code for iOS8 and above
}
else
{
// Code for iOS7 and below
}



Или используйте системную константу NSFoundationVersionNumber_iOS_7_1, как показано ниже

if(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
{
   // Code for iOS8 and above
}
else
{
   // Code for iOS7 and below
}


дополнительные параметры Link

person Jageen    schedule 26.08.2014
comment
Не надо -1 :)), кто делал, поделитесь своими мыслями с другими - person Jageen; 23.09.2014
comment
Плохая практика, никогда не сверяйтесь с номерами версий. Всегда проверяйте возможности/функции. - person SHaKie; 15.10.2014
comment
@SHaKie, тогда в этом случае полезно использовать константу NSFoundationVersionNumber_iOS_7_1, предоставленную Apple. - person Jageen; 15.10.2014
comment
Лучше всего проверить, существует ли класс, как в моем ответе, опубликованном выше. Для методов вы также можете проверить, что класс отвечает на @selector(yourMethod) - person Erwan; 16.10.2014
comment
@Джагин, боюсь, что нет. Это просто плохая практика — сверяться с номерами версий ОС, как бы вы это ни делали. Никогда не следует жестко кодировать зависимости таким образом, всегда проверяйте функции, возможности или существование класса. Учти это; Apple может выпустить обратно совместимую версию класса, если они это сделают, то предлагаемый вами код никогда не будет использовать его, поскольку ваша логика ищет номер версии ОС, а НЕ существование класса. - person SHaKie; 19.10.2014

Я создал очень простую обертку на Objective-C, которая поддерживает как старый iOS UIAlertView, так и новый UIAlertViewController

https://github.com/MartinPerry/UIAlert/

Это также приводит к использованию новых блоков действий в старом UIAlertView.

Образец:

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];
person Martin Perry    schedule 15.12.2014
comment
Обрабатывает ли это несколько предупреждений? - person palme; 05.10.2015

Я написал один класс, который обертывает UIAlertView и использует UIAlertController. Для программиста прозрачно, поэтому достаточно импортировать эти классы в проект. Полезность этих классов заключается в том, что в старом проекте нужно изменить больше UIAlertView. Ссылка: https://github.com/kennymuse/UIAlertView

person kennymuse    schedule 29.10.2015

Способ первый

по проверке версии системы ios

#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
}

Способ второй

по обнаружению системной функции

// create UIActionController 
if([UIActionController class]){
    // todo
// create UIAlertView
}else{
    // todo
}

Но есть и третья библиотека с именем PSTAlertController, которая обеспечивает обратную совместимость с iOS 7 UIActionSheet и UIAlertView.

ссылка на

person monjer    schedule 05.12.2014

Попробуйте код ниже. Он отлично работает как для 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];
}
person amitshinik    schedule 24.06.2016