J'utilise Swift pour écrire une application et je dois afficher une alerte. L'application doit être compatible iOS 7 et iOS 8. Puisque UIAlertView
a été remplacé par UIAlertController
, comment puis-je vérifier si UIAlertController
est disponible sans vérifier la version du système? J'ai entendu dire qu'Apple recommandait de ne pas vérifier la version du système de l'appareil afin de déterminer la disponibilité d'une API.
C’est ce que j’utilise pour iOS 8, mais cela se bloque sur iOS 7 avec "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)
Si j'utilise UIAlertView pour iOS 8, je reçois cet avertissement: Warning: Attempt to dismiss from view controller <_UIAlertShimPresentingViewController: 0x7bf72d60> while a presentation or dismiss is in progress!
Le modèle de détection est identique au style Objective-C.
Vous devez détecter si le runtime actif en cours est capable d'instancier cette classe.
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
}
N'essayez pas de résoudre ce problème en vous basant sur la version du système d'exploitation. Vous devez détecter des capacitésPASOS.
MODIFIER
Le détecteur d'origine pour cette réponse NSClassFromString("UIAlertController")
échoue sous l'optimisation -O
et a donc été remplacé par la version actuelle qui fonctionne pour les versions Release
EDIT 2
NSClassFromString
fonctionne avec toutes les optimisations dans Xcode 6.3/Swift 1.2
Pour le code non-Swift, objectif-C pur le fait
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];
}
J'étais ennuyé de devoir écrire dans les deux situations, j'ai donc écrit un contrôleur UIAlert compatible qui fonctionne également pour iOS 7; J'ai fait de mon mieux pour reproduire les méthodes (bien meilleures) d'ajout de boutons et d'actions de UIAlertController. Fonctionne à la fois avec Objective-C et Swift. Je poste ceci car j'ai trouvé cette question lors d'une recherche sur Google et j'ai pensé que cela pourrait être utile pour les autres.
Vous pouvez résoudre votre problème en utilisant ce code: -
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)
}
et UIKit devait être marqué comme facultatif plutôt que obligatoire.
Courtsey: - Alerte pouvant fonctionner sur iOS 7 et iOS 8
Swift 2.0
if #available(iOS 8.0, *) {
} else {
}
S'il s'agit de code partagé et qu'il est possible que le code puisse être utilisé dans une extension iOS 8 (où UIAlertView et UIActionSheet sont des API restreintes), ainsi que dans iOS 7, où UIAlertController n'existe pas, consultez: JVAlertController
Il s’agit d’un port arrière d’UIAlertController pour iOS 7 compatible avec les API, que j’ai entrepris de rendre le code SDK sûr pour une utilisation dans les extensions iOS 7 et iOS 8.
Vous pouvez utiliser une catégorie pour résoudre ce problème (bien que vous deviez le convertir en 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
Ensuite, il suffit d'appeler
[UIView showSimpleAlertWithTitle: @"Error" message: message cancelButtonTitle: @"OK"];
Mais si vous ne voulez pas vérifier la version du système, utilisez simplement
BOOL lowerThaniOS8 = NSClassFromString( @"UIAlertController" ) == nil;
dans la catégorie UIView (AlertCompatibility)
Si vous utilisez à la fois iOS 7- UIAlertView et iOS 8+ UIAlertController comme décrit ci-dessus et que vous voulez que votre méthode UIAlertController appelle le délégué de votre UIAlertView (par exemple, MyController) alertView: didDismissWithButtonIndex pour continuer à traiter les résultats, voici un exemple de procédure cette:
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];
}
];
...
Ceci utilise la recommandation d’Apple pour la capture de auto dans un bloc: Évitez les cycles de référence élevés lors de la capture d’auto
Bien sûr, cette méthode suppose que vous n’ayez qu’un seul UIAlertView dans le contrôleur et que vous transmettez par conséquent la valeur nil à la méthode déléguée. Sinon, vous devez instancier (et marquer) un "faux" UIAlertView à transmettre à alertView: didDismissWithButtonIndex.
Ici pour vérifier deux façons de UIAlertView
et UIAlertContoller .
Vérification 1: Vérification de la version iOS UIAlertController Class.
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()
}
Vérification 2: vérifiez UIAlertController
nil, puis la version iOS inférieure à 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()
}
Si vous souhaitez être compatible avec iOS 7, n'utilisez pas UIAlertController
. Aussi simple que cela.
UIAlertView
n'a pas été remplacé, il fonctionne toujours parfaitement et continuera de fonctionner parfaitement dans un avenir proche.
Voici ma solution Swift drag and drop:
//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()
}
}
Appelle comme ça:
CozAlert("reportTitle", message: "reportText", action: "reportButton", sender: self)
Attention, cela ne concerne que les alertes les plus élémentaires. Vous aurez peut-être besoin de code supplémentaire pour les éléments avancés.