AlertView 注意点

2018-09-18  本文已影响25人  kamto

在项目中遇到了一些关于alertView的小问题。虽然UIAlertView在iOS9.0已经过时了,在iOS8.0被新的UIAlertController所取代,但兼顾以前的系统UIAlertView仍然用得不少。

1.

使用UIAlertView弹窗时,如果接下来使用到[UIApplication sharedApplication].keyWindow来获取当前主屏幕时,系统会使用一个新的window来展现UIAlertView,当前keyWindow会被替换。

[self.alertView show];
NSLog(@"Class :  %@", NSStringFromClass([[UIApplication sharedApplication].keyWindow class]));
NSLog(@"view Class :  %@", [UIApplication sharedApplication].keyWindow.rootViewController);

会打印
Class : _UIAlertControllerShimPresenterWindow
Class : <UIApplicationRotationFollowingController: 0x1035358e0>

而此时根据[UIApplication sharedApplication].keyWindow.rootViewController 将不是当前屏幕根控制器,如果此时在代理方法里再使用一个继承于UIWindow的子类时,如ToastView : UIWindow,此后获取keyWindow的时候keyWindow会被ToastView替换

NSLog(@"Class :  %@", NSStringFromClass([[UIApplication sharedApplication].keyWindow class]));
NSLog(@"view Class :  %@", [UIApplication sharedApplication].keyWindow.rootViewController);

Class : ToastView
Class : (null)

所以我们应该避免在alertView弹窗时使用keyWindow,而是使用[UIApplication sharedApplication].delegate.window

NSLog(@"Class :  %@", NSStringFromClass([[UIApplication sharedApplication].delegate.window class]));
[self.alertView show];
NSLog(@"Class :  %@", NSStringFromClass([[UIApplication sharedApplication].delegate.window class]));
NSLog(@"view Class :  %@", [UIApplication sharedApplication].delegate.window.rootViewController);

打印:
Class : UIWindow
Class : UIWindow
Class : <ViewController: 0x135d0b700>

总结:

1、在UIAlertView没有show之前,delegate.window和keyWindow内存地址是一致的,表示当前的keyWindow就是应用的window,一般情况下,两者是同一个。
2、在UIAlertView show之后,keyWindow发生了变化,已经被系统替换为新的window,这个新的window用来展示UIAlertView,但是此时delegate.window还是原来的那个。如果使用keyWindow的获取应用控制器的时候,最好将keyWindow改成delegate.window。

2.

使用UIAlertController则不会有这问题,弹窗时并不会改变keyWindow

[self presentViewController:self.alertController animated:YES completion:nil];
NSLog(@"Class :  %@", NSStringFromClass([[UIApplication sharedApplication].keyWindow class]));

打印:
Class : UIWindow

3.

如果要同时弹出多个alertview时
如果使用UIAlertView,会先展现最新弹窗,点击消失后,继续弹出之前的弹窗,

[alertView1 show];
[alertView2 show];

如果使用UIAlertController时,因为它继承UIViewController,它们的页面跳转都是使用的present方法。第一个UIAlertController跳转后,相当于当前最上层的页面是alertController1的页面,因此,此时想再增加一个UIAlertController,必须在alertController1上跳转。

viewController presentViewController:alertController1 animated:YES completion:nil];
[alertController1 presentViewController:alertController2 animated:YES completion:nil];
4.

当我们在键盘收起时使用alertView弹窗时会发现键盘收起马上alert弹窗,但收起alert时,键盘会出现并再收起。这是因为textField取消第一响应者后立刻执行弹出alert,打断键盘收起动画,在alert完后会再执行一遍键盘收起动画,解决办法是先需要获取键盘收起的时间,根据这个时间延迟执行alertView弹窗。使用UIAlertController则不会有这个问题。

分享一道面试题

@interface Son : Father

@end

- (instancetype)init{
    if (self = [super init]) {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}

都会打印:
Son
Son

原因:

调用[self class]的时候会去self的isa所指向的Son类对象中寻找该方法,在没有重载[obj class]的情况下, Son类对象是没有这个方法的,此时会接着在父类对象的方法列表中查找,最终会发现NSObject存储了该方法,所以[self class]会返回实例对象(self)所属的Son这个类对象。

[super class]则指定从父类Father的方法列表开始去查找- (Class)class这个方法,显然Father没有这个方法,最终还是要查找到NSObject类对象的方法列表中,需要注意的是不管是[self class]还是[super class], 它们都是调用的实例对象的- (Class)class方法,虽然其指向的类对象不同,但实例对象都是self本身,再强调下区分开实例对象和类对象!因而返回的也是当前self的isa所指向的Son类。super是objc_super类型的结构体,它包含了当前的实例对象self以及父类的类对象。

上一篇下一篇

猜你喜欢

热点阅读