在iOS 7中找到没有引用的UIAlertView

12

我在我的项目中使用了一个代码片段,答案在这里: 没有引用的UIAlertView

这是代码:

+ (UIAlertView *) getUIAlertViewIfShown {
    if ([[[UIApplication sharedApplication] windows] count] == 1) {
        return nil;
    }

    UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    if ([window.subviews count] > 0) {
        UIView *view = [window.subviews objectAtIndex:0];
        if ([view isKindOfClass:[UIAlertView class]]) {
            return (UIAlertView *) view;
        }
    }
    return nil;
}

很不幸,它在iOS 7中无法工作,并且我无法解除警告视图。调试时,我发现在循环中显示的视图是UITransitionView类。非常令人困惑,因为我找不到这个视图类的快速文档。

有任何想法如何解决这个问题吗?


7
只需保留对它的引用。 - Kevin
有可能还有更多的窗口吗?你只检查了一个窗口,为什么不检查所有的窗口呢? - rmaddy
@Kevin 我正在使用宏来显示警告视图,而且使用频率太高了。你的建议将是最后的选择。 - Abdullah Umer
@rmaddy 我调试了代码,发现在Windows系统上只返回了一个数组对象。 - Abdullah Umer
5个回答

16
在iOS7中,UIAlertView窗口不会出现在-[UIApplication windows]中。实际上,UIAlertView本身从未添加到任何窗口,-[UIAlertView window]始终为nil。相反,警报视图管理各种未记录的视图,这些视图放置在-[UIApplication keyWindow]中,并且没有任何引用返回到警报视图。
您在iOS7中唯一的选择是实际跟踪您的警报视图。

我修改了所有的代码并保留了警告视图的引用,现在它们都可以正常工作了。 - Abdullah Umer
UIAlertView的窗口是-UIModalItemHostingWindow(私有API)。 - Mehul Thakkar

15

iOS 7 解决方案

Class UIAlertManager = objc_getClass("_UIAlertManager");
UIAlertView *topMostAlert = [UIAlertManager performSelector:@selector(topMostAlert)];

我不确定它是否能通过AppStore的审核,但是它可以正常运行。

更新:单行代码:

UIAlertView *topMostAlert = [NSClassFromString(@"_UIAlertManager") performSelector:@selector(topMostAlert)];

2
我可以使用NSClassFromString代替objc_getClass吗? - Tung Do
这个通过审核了吗? - Chris Mitchelmore
苹果公司允许吗?@TùngĐỗ - Rushi
这是苹果允许的吗?请告诉我们。@TùngĐỗ - Rushi
3
当然,这在生产中是不允许的。对于集成测试可能会有帮助,但在模拟器上似乎行不通。也许7.1版本解决了这个问题。 - binarymochi
1
上传到App Store时出现错误,引用了非公共API。它无法正常工作。 - Ankit Jain

1

我曾面临过类似的问题,在我的情况下,警报是从不同实例的视图控制器中显示的。正如Brian已经提到的那样,在iOS 7中,UIAlertView窗口不会出现在-[UIApplication windows]中。

因此,可以采用以下方法来跟踪这个问题 -

  1. 在应用程序委托中定义一个BOOL常量 -

    @property (nonatomic, assign) BOOL isAlertVisibleOnAppWindow;
    
  2. 在'UIAlerView`存在的情况下,检查先前的实例是否存在 -

    AppDelegate *delegate = (AppDelegate *) [UIApplication sharedApplication].delegate;
    if (!delegate.isAlertVisibleOnAppWindow) {
        delegate.isAlertVisibleOnAppWindow = YES;
    
        UIAlertView *alertView = [[UIAlertView alloc] init…//alert init code
    
        //要么通过块处理警报取消/完成单击,要么使用警报委托将isAlertVisibleOnAppWindow BOOL变量重置为NO。
    }
    
这可能对其他人有所帮助,想分享一下。

0

您可以注册 UIWindowDidBecomeVisibleNotification

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(aWindowBecameVisible:)
                                             name:UIWindowDidBecomeVisibleNotification
                                           object:nil];

在 aWindowBecameVisible 中,检查窗口描述中的 _UIModalItemHostingWin:_UIModalItemHostingWin
if ([[theWindow description] hasPrefix:@"<_UIModalItemHostingWin"])
{
    // This is the alert window
}

0
UIAlertView *topMostAlert = [NSClassFromString(@"_UIAlertManager") performSelector:@selector(topMostAlert)];

这将不被允许发布到苹果商店。在构建验证期间,Xcode会抛出一个错误,类似于:“访问未记录的方法..” 所以你不能使用它,但是这段代码可以正常工作。


上传到App Store时出现错误,引用了非公共API。它无法正常工作。 - Ankit Jain
1
完美的方式...如果您不想在App Store上上传您的应用程序。 - Mehul Thakkar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接