我正在使用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 for iOS 8,我会收到此警告:Warning: Attempt to dismiss from view controller <_UIAlertShimPresentingViewController: 0x7bf72d60> while a presentation or dismiss is in progress!
答案 0 :(得分:76)
检测模式与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
}
请勿尝试根据操作系统版本来解决此问题。您需要检测能力不操作系统。
编辑
此答案NSClassFromString("UIAlertController")
的原始检测器在-O
优化下失败,因此已将其更改为适用于发布版本的当前版本
编辑2
NSClassFromString
正在Xcode 6.3 / Swift 1.2的所有优化中工作
答案 1 :(得分:29)
对于非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];
}
答案 2 :(得分:9)
我很生气,我不得不写出两种情况,所以我写了一个兼容的UIAlertController,适用于iOS 7,所以我把它扔在GitHub上。我尽力复制(更好)添加UIAlertController的按钮和动作的方法。适用于Objective-C和Swift。我正在发布这个,因为我在Google上搜索时发现了这个问题,并认为这对其他人有帮助。
答案 3 :(得分:8)
您可以使用以下代码解决问题: -
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必须标记为Optional而不是Required。
Courtsey: - Alert that can work on iOS 7 and iOS 8
答案 4 :(得分:6)
Swift 2.0
if #available(iOS 8.0, *) {
} else {
}
答案 5 :(得分:4)
如果这是共享代码,并且代码可能在iOS 8扩展中使用(其中UIAlertView和UIActionSheet是受限制的API)以及iOS 7,其中UIAlertController不存在,请查看:JVAlertController
它是iOS 7的UIAlertController的API兼容后端,我承诺使SDK代码可以安全地用于iOS 7和iOS 8扩展。
答案 6 :(得分:2)
您可以使用类别来解决这个问题(尽管您需要将其转换为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)
答案 7 :(得分:2)
如果您同时使用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 :Avoid Strong Reference Cycles when Capturing self
当然,此方法假设您在控制器中只有一个UIAlertView,因此将nil作为其值传递给委托方法。否则,您需要实例化(并标记)“假”UIAlertView以传递给alertView:didDismissWithButtonIndex。
答案 8 :(得分:1)
此处检查UIAlertView
和UIAlertContoller的两种方式。
检查1: iOS版本检查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()
}
答案 9 :(得分:0)
如果您想与iOS 7兼容,请不要使用UIAlertController
。就这么简单。
UIAlertView
尚未被替换,它仍然完美无缺,并且在可预见的未来将继续完美运作。
答案 10 :(得分:0)
这是我的拖放快速解决方案:
//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)
请注意,这仅适用于最基本的警报,您可能需要其他高级内容代码。
答案 11 :(得分:-1)
尝试以下代码。它适用于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];
}
答案 12 :(得分:-2)
在iOS8中,有一个新类UIAlertController
取代UIAlertView
和UIActionSheet
。从iOS8开始,使用UIAlertController,对于iOS8,然后使用UIAlertView和UIActionSheet。我认为iOS8添加size classes
更改UIAlertView
显示方向。请参阅:https://github.com/wangyangcc/FYAlertManage
答案 13 :(得分:-2)
从此link下载警报课程 并且可以轻松地用于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];