UIAlertController中block使用出现的问题

自iOS 8.0 以及以后的版本,API推荐使用UIAlertCtroller.

一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
id sendAlert(id object){
NSString *text=[NSString stringWithFormat:@"%@",object];
NSString *button=[NSBundle localizedString:@"ZHIDAOLE"];
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.message=nil;
[alert addButton:button withBlock:nil];
[alert show];
return alert;
}else{
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=nil;
UIAlertAction *action = [UIAlertAction actionWithTitle:button style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:action];
UIViewController *root = [UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
return alert;
}
return nil;
}
id sendAlertBlock(id object,dispatch_block_t block){
NSString *text=[NSString stringWithFormat:@"%@",object];
NSString *button=[NSBundle localizedString:@"ZHIDAOLE"];
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.message=nil;
[alert addButton:button withBlock:block];
[alert show];
return alert;
}else{
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=nil;

UIAlertAction *action=[UIAlertAction actionWithTitle:button style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[alert dismissViewControllerAnimated:YES completion:^{}];
if (block) {
block();
}
}];
[alert addAction:action];
UIViewController *root=[UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
return alert;
}
return nil;
}

id sendToast(id object){
return sendToastWithTimeout(object, 2);
}
id sendToastWithTimeout(id object,NSTimeInterval timeout){
NSString *text=[NSString stringWithFormat:@"%@",object];
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.message=nil;
[alert show];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[alert dismissWithClickedButtonIndex:-1 animated:YES];
});
return alert;
}else{
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=nil;
UIViewController *root=[UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:^{}];
});
return alert;
}
return nil;
}

id sendConfirm(id object,dispatch_block_t block){
dispatch_block_t non=^{};
return sendConfirm2(object, block, non);
}
id sendConfirm2(id object,dispatch_block_t yesblock,dispatch_block_t noblock){
NSString *text=[NSString stringWithFormat:@"%@",object];
NSString *confirm=[NSBundle localizedString:@"QUEDING"];
NSString *cancel=[NSBundle localizedString:@"QUXIAO"];
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.message=nil;
[alert addButton:confirm withBlock:yesblock];
[alert addButton:cancel withBlock:noblock];
[alert show];
return alert;
}else{
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=nil;

UIAlertAction *actionConfirm=[UIAlertAction actionWithTitle:confirm style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (yesblock) {
yesblock();
}
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:^{}];
});
}];
[alert addAction:actionConfirm];

UIAlertAction *actionConcel=[UIAlertAction actionWithTitle:cancel style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (noblock) {
noblock();
}
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:^{}];
});
}];
[alert addAction:actionConcel];
UIViewController *root=[UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
return alert;
}
return nil;
}

id sendTask(id object,dispatch_block_t block){
NSString *text=[NSBundle localizedString:@"QINGSHAOHOU"];
if (object) {
text=[NSString stringWithFormat:@"%@",object];
}
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.message=nil;
[alert show];
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue=dispatch_queue_pool("serial.alert", NULL);
});
[[UIApplication sharedApplication] setNetworkActivity:YES];
dispatch_async(queue, ^{
if (block) {
block();
}
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivity:NO];
[alert dismissWithClickedButtonIndex:-1 animated:YES];
});
});
return alert;
}else{
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=nil;
UIViewController *root=[UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue=dispatch_queue_pool("serial.alert", NULL);
});
[[UIApplication sharedApplication] setNetworkActivity:YES];
dispatch_async(queue, ^{
if (block) {
block();
}
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:^{}];
[[UIApplication sharedApplication] setNetworkActivity:NO];
});
});
return alert;
}
return nil;
}
id sendTaskWithCallback(id object,UIAlertViewBlock block){
NSString *text=[NSBundle localizedString:@"QINGSHAOHOU"];
if (object) {
text=[NSString stringWithFormat:@"%@",object];
}
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
if (!block) {
block=^(UIAlertView *alertView){};
}

UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.message=@"-";
[alert show];
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue=dispatch_queue_pool("serial.alert", NULL);
});
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivity:YES];
});
block(alert);
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivity:NO];
[alert dismissWithClickedButtonIndex:-1 animated:YES];
});
});
return alert;
}else{
if (!block) {
block=^(UIAlertController *alertView){};
}
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=@"-";
UIViewController *root=[UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue=dispatch_queue_pool("serial.alert", NULL);
});
dispatch_async(queue, ^{
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivity:YES];
});
block(alert);
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setNetworkActivity:NO];
[alert dismissViewControllerAnimated:YES completion:nil];
});
});
return alert;
}
return nil;
}
id sendLongTaskWithCallback(id object,UIAlertViewBlock block){
if (!block) {
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
block=^(UIAlertView *alertView){};
}else{
block=^(UIAlertController *alertView){};
}
}
UIAlertViewBlock newblock=^(id alertView) {
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
});
block(alertView);
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
});
};
return sendTaskWithCallback(object, newblock);
}

id sendInputAlert(id object,UIAlertViewStyle style,UIAlertViewBlock block){
NSString *text=[NSString stringWithFormat:@"%@",object];
NSString *confirm=[NSBundle localizedString:@"QUEDING"];
NSString *cancel=[NSBundle localizedString:@"QUXIAO"];
if (!SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
UIAlertDialog *alert=[[UIAlertDialog alloc] init];
alert.title=text;
alert.alertViewStyle=style;
[alert addButton:confirm withAlertBlock:block];
[alert addButton:cancel withBlock:nil];
[alert show];
return alert;
}else{
UIAlertController *alert=[UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleAlert];
alert.title=text;
alert.message=nil;

switch (style) {
case UIAlertViewStyleSecureTextInput:
{
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.secureTextEntry = YES;
textField.borderStyle = UITextBorderStyleLine;
}];
}
break;

case UIAlertViewStylePlainTextInput:
{
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.borderStyle = UITextBorderStyleLine;
}];
}
break;

case UIAlertViewStyleLoginAndPasswordInput:
{
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.secureTextEntry = YES;
textField.borderStyle = UITextBorderStyleLine;
}];
[alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.borderStyle = UITextBorderStyleLine;
}];
}
break;

default:
break;
}

UIAlertAction *actionConfirm=[UIAlertAction actionWithTitle:confirm style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (block) {
block(alert);
}
dispatch_async(dispatch_get_main_queue(), ^{
[alert dismissViewControllerAnimated:YES completion:^{}];
});
}];
[alert addAction:actionConfirm];

UIAlertAction *actionConcel=[UIAlertAction actionWithTitle:cancel style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[alert dismissViewControllerAnimated:YES completion:^{}];

}];
[alert addAction:actionConcel];
UIViewController *root=[UIApplication sharedApplication]. keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:^{}];
return alert;
}
return nil;
}

Analysis

分析如下:

  1. iOS 8.0以及以后的版本,API内推荐使用UIalertController;
  2. 但是8.0以前的版本,会经常出现键盘跳来跳去的问题;
  3. 为了兼容两个版本,写出来上述代码。

但是:

1.设置弹出消息时,按照上面的代码来写的,有一个问题,当在一个sendAlert里面弹出一个新的alert时,原来的alert是被present出来的,没有消失掉,又要弹出新的alert,app终端就会提示已经有一个模态推出的视图;为了让它可以被推出;

2.我又在present的时候做了判断,判断当前的window的rootWindow,是否有presentedViewController并且这个Controller的状态是否是isBeDismissed,有值且没有被dismiss,那有就先dismiss掉,之后再调用presented方法;但问题还在,有时会出现还没有dismiss掉,present的动作就又发起了;

3.又重新找了一个方法,依然判断是否存在presentedViewController并且这个Controller的状态是否是isBeDismissed,有值且没有被dismiss,那有就先dismiss掉,在dismiss的结束block里面去present新的alert,没有的就直接present出来,这样,这个问题就避免了。

然并卵

领导说,这样做其实很费力的,感觉会遗留很多问题出来(我是有点儿说不清楚,至少window这个角色我就觉得有些问题),所以没有做。

我觉得,后续可以看三方的比较好的alert的处理方案,借鉴代码也是可以的,只要逻辑相通,代码的修改量不大,都是可以接受的。

总结

突然就对UIWindow这个东西感兴趣,想要做出一个类似于UIAlertView的东西,来兼容两个版本,可我发现,UIWindow在makeKeysAndVisible这个方法上,必须要有rootViewController使我非常不明白,后续弄清楚了,再继续补充说明吧。