防止多個(gè)UIAlertView重疊彈出

項(xiàng)目中可能會(huì)遇到這種情況,好幾個(gè)alertView因?yàn)檫壿嬯P(guān)系全部彈出,用戶需要一個(gè)個(gè)的點(diǎn)擊才能將所有的alertView取消掉。或者說這種情況下,我們只需要彈出一個(gè)alertView就OK了。

alertView是怎么彈出的?網(wǎng)上查找資料說是,每次執(zhí)行[alertView show],這個(gè)方法的時(shí)候是新建了一個(gè)window,將alertView顯示在了window上面。代碼驗(yàn)證的確是這樣的。

代碼驗(yàn)證alertView是添加到哪里的。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    tempBtn.frame = CGRectMake(100, 100, 100, 100);
    tempBtn.backgroundColor = [UIColor cyanColor];
    [tempBtn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:tempBtn];
    
}

- (void)clickBtn:(UIButton *)sender
{
    UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:@"title1" message:@"message1" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
    [alert1 show];
    
 NSLog(@"alert1.window = %@   alert1.window.windowLevel = %f",alert1.window,alert1.window.windowLevel);
    NSLog(@"app.window = %@",app.window);
    NSLog(@"windows == %@",[UIApplication sharedApplication].windows);
}

測(cè)試結(jié)果:

alert1.window = <_UIAlertControllerShimPresenterWindow: 0x7f9ee8c07940; frame = (0 0; 414 736); opaque = NO; gestureRecognizers = <NSArray: 0x618000056aa0>; layer = <UIWindowLayer: 0x6180000240a0>>   alert1.window.windowLevel = 2001.000000
app.window = <UIWindow: 0x7f9ee8f03f80; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x608000052f60>; layer = <UIWindowLayer: 0x608000022100>>
 windows == (
    "<UIWindow: 0x7f9ee8f03f80; frame = (0 0; 414 736); autoresize = W+H; gestureRecognizers = <NSArray: 0x608000052f60>; layer = <UIWindowLayer: 0x608000022100>>"
)

通過打印的結(jié)果可以看出:
1、alert1.window沒有在[UIApplication sharedApplication].windows中出現(xiàn)<window和windows的關(guān)系參考:http://www.lxweimin.com/p/75befce85623>,windows中只有app.window也就是當(dāng)前的最底層的控件。
2、alert1.window的windowLevel是2001比app.window的大,APP.window的windowLevel是0,所以alertView顯示在了app.window的上面。相關(guān)windowLevel的問題參考:http://www.lxweimin.com/p/f60471a7d935

搞懂了alertView顯示的大致原理了,那么往我們的需求上靠

- (void)clickBtn:(UIButton *)sender
{
    UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:@"title1" message:@"message1" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
    [alert1 show];
    
    UIAlertView *alert2 = [[UIAlertView alloc] initWithTitle:@"title2" message:@"message2" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
    [alert2 show];
    
    
//    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
//    
//    NSLog(@"alert1.window = %@   alert1.window.windowLevel = %f",alert1.window,alert1.window.windowLevel);
//    NSLog(@"app.window = %@",app.window);
//    NSLog(@"windows == %@",[UIApplication sharedApplication].windows);
}

想要多余的alertView不顯示,兩種方法:
1、要么讓他不展示
2、要么讓他展示了自己再消失
第一種我感覺做不到,顯示的邏輯是寫死的。
那就拿第二種下手,前提是怎么獲取到已經(jīng)展示的alertView?

上面介紹的alertView顯示,是顯示在系統(tǒng)給自己創(chuàng)建的Window上面的,但是這個(gè)window還獲取不到。那怎么辦。
有這么一種思路,將所有顯示的alertView記錄在自己的一個(gè)數(shù)組中,然后不就想干嘛就干嘛了嘛!!關(guān)鍵點(diǎn)是記錄的時(shí)機(jī),這里選取show方法執(zhí)行的時(shí)候
思路1:
使用runtime方法檢測(cè)show方法,然后在執(zhí)行show方法的時(shí)候記錄alertView,相關(guān)代碼如下:
創(chuàng)建記錄alertView的單例

#import <Foundation/Foundation.h>

@interface AlertViewRecorder : NSObject

@property (nonatomic, strong)NSMutableArray * alertViewArray;

+ (AlertViewRecorder *)shareAlertViewRecorder;

@end
#import "AlertViewRecorder.h"

@implementation AlertViewRecorder
// 創(chuàng)建單例,記錄alertView
+ (AlertViewRecorder *)shareAlertViewRecorder
{
    static AlertViewRecorder *recoder = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if(recoder == nil){
            recoder = [[AlertViewRecorder alloc] init];
            
        }
    });
    return recoder;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.alertViewArray = [[NSMutableArray alloc] init];
    }
    return self;
}

@end

關(guān)鍵代碼

#import "UIAlertView+MyAlertView.h"
#import <objc/message.h>
#import "AppDelegate.h"
#import "AlertViewRecorder.h"

@implementation UIAlertView (MyAlertView)

+ (void)load
{
    // 獲取將要交換的兩個(gè)方法
    Method showMethod = class_getInstanceMethod(self, @selector(show));
    Method myShowMethod = class_getInstanceMethod(self, @selector(myShow));
    // 將兩個(gè)方法互換
    method_exchangeImplementations(showMethod, myShowMethod);
    
}

- (void)myShow
{
    // 將之前所有的alertView取出來消失掉
    NSMutableArray *array =  [AlertViewRecorder shareAlertViewRecorder].alertViewArray;
    for (UIAlertView *alertView in array) {
        if ([alertView isKindOfClass:[UIAlertView class]]) {
            [alertView dismissWithClickedButtonIndex:-1 animated:YES];
        }
    }
    
    [array removeAllObjects];
    // 調(diào)用自身的方法
    [self myShow];
    [array addObject:self];
}

@end

測(cè)試代碼可行;

思路2:
創(chuàng)建分類,重寫show方法,在重寫的show方法中調(diào)用show方法的同時(shí),記錄alertView到相關(guān)數(shù)組,和思路1差不多。

思路1相對(duì)于思路2的優(yōu)點(diǎn),個(gè)人認(rèn)為,當(dāng)項(xiàng)目開發(fā)了一段時(shí)間或者半路接手項(xiàng)目的時(shí)候,思路1更有優(yōu)勢(shì)。

如有失誤請(qǐng)各位路過大神即時(shí)指點(diǎn),或有更好的做法,也請(qǐng)指點(diǎn)一二,在下感激不盡。
代碼連接:https://github.com/RunOfTheSnail/MyAlertViewDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容