【问题标题】:iOS/Objective-C: Call AlertViewController from sharedInstanceiOS/Objective-C:从 sharedInstance 调用 AlertViewController
【发布时间】:2019-01-28 22:15:49
【问题描述】:

我正在将一些自 iOS 9.0 以来已弃用的 UIAlertViews 更新为 UIAlertViewControllers。

使用 UIAlertView,可以从任何正在执行的代码中抛出警报——即使是在实用程序类或共享实例中——只需一行:

[alertView show];

所以如果我调用一个共享实例,比如

- (void)didTapDeleteButton:(id)sender {
    NSArray *itemsToDelete = [self.selectedIndexPathToContact allValues];

    [[IDModel sharedInstance] deleteItems:itemsToDelete];

//其中包含代码:

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Keep Archive Copy?"
                                                    message:nil
                                                   delegate:self
                                          cancelButtonTitle:@"No"
                                          otherButtonTitles:@"OK",nil];
alertInvite.alertViewStyle = UIAlertViewStyleDefault;
alertInvite.tag=100;
[alertView show];

一切正常。

但是,对于 UIAlertController,这是不允许的。如果将以下代码放在通过共享实例可访问的类的方法中,当您到达 presentViewController 时,会抛出错误:

UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"Delete Item?" message:nil preferredStyle:UIAlertControllerStyleAlert];

UIAlertAction* yesButton = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
    [alertView dismissViewControllerAnimated:YES completion:nil];
}];

UIAlertAction* noButton = [UIAlertAction actionWithTitle:@"Not Now" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
    [alertView dismissViewControllerAnimated:YES completion:nil];
}];

[alertView addAction:noButton];
[alertView addAction:yesButton];
if ([alertView respondsToSelector:@selector(setPreferredAction:)]) {
    [alertView setPreferredAction:yesButton];
}
//FOLLOWING THROWS ERROR
[self presentViewController:alertView animated:YES completion:nil];

在最后一行,类(通过共享实例访问)没有此方法。看来您必须使用更复杂的方式来引发警报。我见过一些somwehat convoluted approaches,例如:

id rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
if([rootViewController isKindOfClass:[UINavigationController class]])
{
    rootViewController = ((UINavigationController *)rootViewController).viewControllers.firstObject;
}
if([rootViewController isKindOfClass:[UITabBarController class]])
{
    rootViewController = ((UITabBarController *)rootViewController).selectedViewController;
}
[rootViewController presentViewController:alertInvite animated:YES completion:nil];

但是,这对我不起作用,因为我认为我的共享实例没有 rootviewcontroller。谁能提出一个简单直接的方法来做到这一点?

【问题讨论】:

  • 你指的是什么sharedInstance? Edit您的问题(没有 cmets),在您需要致电 [self presentViewController... 的地方有更多的上下文。
  • self in [self presentViewController 必须是 UIViewController
  • 他说 sharedInstance 没有 present 方法,所以我推断它是任何随机的 NSObject 而不是 VC
  • 查看@rmaddy 要求的其他代码
  • 是的,sharedInstance是一个NSObject

标签: ios objective-c uialertviewcontroller


【解决方案1】:

我相信你的问题很模糊。但我认为您一直在寻找的是展示UIAlertController 的示例。那是对的吗?如果是这样,请继续阅读...

例子:

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"message" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction: [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:nil]];
alert.TitleColor = [UIColor whiteColor];
[self presentViewController:alert animated:YES completion:nil];

文档:https://developer.apple.com/documentation/uikit/uialertcontroller

【讨论】:

  • 操作的问题是他在单例中。可能不是视图控制器
【解决方案2】:

从我能想到的任何代码中显示警报:

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Alert" message:@"message" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction: [UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:nil]];
alert.TitleColor = [UIColor whiteColor];

id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate;
UIViewController *vc = delegate.window.rootViewController;
[vc presentViewController:alert animated:YES completion:nil];

注意:

请注意,在大多数情况下,我不会这样做。
非ui代码不应该做ui!这可能也是苹果做出改变的部分原因:它鼓励适当的模型||视图分离

【讨论】:

  • 你会向视图控制器发送通知吗?或者你会如何告诉屏幕上的 VC 发出警报?
  • 你不能仅仅假设你可以从应用程序的 rootViewController 显示警报。那可能已经呈现了一个视图控制器。
  • 你也不能假设调用 self ;) 但样本也确实如此 hehe 我承认它可能不是在所有情况下都是正确的,我认为我的注意段落暗示我不同意
  • 正确的方法是根本不这样做,而是将 UI 保留在 View&Controller 而不是模型中
  • 在通知之上使用完成块或委托协议 :) 我通常更喜欢这个,因为通知可能很难推理
【解决方案3】:

我在 UIViewController 上创建了一个扩展,它允许我创建一个新窗口并从那里呈现一个视图控制器。这使我可以从任何类进行演示,而不仅仅是视图控制器。此外,它还可以防止您尝试从已经呈现视图控制器的视图控制器显示警报视图的问题。

extension UIViewController {
    func presentFromNewWindow(animated: Bool = true, completion: (() -> Void)? = nil) {
        let window = newWindow()

        if let rootViewController = window.rootViewController {
            window.makeKeyAndVisible()
            rootViewController.present(self, animated: animated, completion: completion)
        }
    }

    private func newWindow() -> UIWindow {
        let window = UIWindow(frame: UIScreen.main.bounds)
        let rootViewController = UIViewController()
        rootViewController.view.backgroundColor = .clear
        window.backgroundColor = .clear
        window.rootViewController = rootViewController
        window.windowLevel = UIWindowLevelAlert

        return window
    }
}

然后您可以使用此方法来展示您的警报控制器(或任何 UIViewController):

alertViewController.presentFromNewWindow()

当您关闭警报视图控制器时,它会从视图控制器中移除,并且窗口也会从层次结构中移除。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多