开发中遇到这样的需求,需要实现在后台接受到某一事件时无论当前用户处在哪个视图都需要弹出一个Alert.
参考了一些网上的资料,加上自己的思考,总结出两种方案:
1)对UIWindow进行扩展
UIWindow+.h
#define UIEventSubtypeMotionShakeNotification @"UIEventSubtypeMotionShakeNotification"
#import <UIKit/UIKit.h>
@interface UIWindow (Motion)
// @override
- (BOOL)canBecomeFirstResponder;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
@end
UIWindow+.m
//
// UIWindow.m
// Demo
//
// Created by simon on 2018/8/18.
// Copyright © 2018年 simon. All rights reserved.
//
#import "UIWindow+.h"
@implementation UIWindow (Motion)
- (BOOL)canBecomeFirstResponder { NSLog(@"csm canBecomeFirstResponder");
return YES;
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"csm motioBegan");
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"csm motionEnded");
[self showAlert];
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
NSLog(@"csm motionCancelled");
}
- (void)showAlert {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
UIViewController *rowVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
//cancle button
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"点击确认");
}]];
[alertController addAction:[UIAlertAction actionWithTitle:@"警告" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
//warn button
NSLog(@"点击警告");
}]];
[alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
NSLog(@"添加一个textField就会调用 这个block");
}];
[rowVC presentViewController:alertController animated:YES completion:nil];
}
@end
Sample usage:
[[UIApplication sharedApplication].keyWindow motionEnded:nil withEvent:nil];
方案思考:
1)在app的 key window上的当前的VC上弹UIAlertController是一个略危险的操作,弹Alert和关Alert会出发当前VC的viewWillAppear/viewDidAppear/viewWillDisappear/viewDidDisappear等,若有逻辑写在这些回调里,可能造成混乱。
2)可能在弹Alert的时候keyWindow根本都不是我们的VC 而是第三方弹的Window,也可能会导致不可控的情况出现。
方案2)对UIAlertController进行扩展
GlobalUIAlertController.h
//
// UIAlertController.h
// Demo
//
// Created by simon on 2018/8/19.
// Copyright © 2018年 simon. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIAlertController(Window)
- (void)show;
- (void)show:(BOOL)animated;
@end
GlobalUIAlertController.m
//
// UIAlertController.m
// Demo
//
// Created by simon on 2018/8/19.
// Copyright © 2018年 simon. All rights reserved.
//
#import "GlobalUIAlertController.h"
#import <objc/runtime.h>
@interface UIAlertController (Private)
@property (strong,nonatomic) UIWindow *alertWindow;
@end
@implementation UIAlertController (Private)
@dynamic alertWindow;
- (void)setAlertWindow:(UIWindow *)alertWindow {
objc_setAssociatedObject(self, @selector(alertWindow),alertWindow, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIWindow *)alertWindow {
return objc_getAssociatedObject(self, @selector(alertWindow));
}
@end
@implementation UIAlertController (Window)
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
self.alertWindow.hidden = YES;
self.alertWindow = nil;
}
- (void)show {
[self show:YES];
}
- (void)show:(BOOL)animated {
self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.alertWindow.rootViewController = [[UIViewController alloc] init];
self.alertWindow.windowLevel = UIWindowLevelAlert + 1;
[self.alertWindow makeKeyAndVisible];
[self.alertWindow.rootViewController presentViewController:self animated:animated completion:nil];
}
@end
Simple usage:
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Title" message:@"Message" preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancle" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action){
NSLog(@"csm");
}]];
[alertController show];
感谢阅读!