Подтвердить что ты не робот

Отобразить UIAlertController из класса UIView/NSObject

У меня working iOS application Для support iOS8 я заменяю UIAlertView/UIActionSheet with UIAlertController.

Проблема:
Для отображения UIAlertController мне нужен presentViewController метод класса UIViewController.
Но UIAlertView отображает из классов inherited от UIView or NSObject,
Я не могу получить метод [self presentViewController...] по понятной причине.

Моя работа:
Я попытался получить текущее окно формы rootViewController и отобразить UIAlertController.

[[[UIApplication sharedApplication] keyWindow].rootViewController presentViewController ...]

но имеют некоторые проблемы с вращением, например, если у моего текущего контроллера вида нет поддержки вращения он будет вращаться, если открыт UIAlertController.

Вопрос:
Кто-нибудь сталкивался с такой же проблемой и имел безопасное решение?
если да, пожалуйста, предоставьте мне пример или дайте какой-нибудь справочник

4b9b3361

Ответ 1

Похоже, что вы в настоящий момент (pre-iOS8) запускаете представление предупреждения из объекта просмотра. Эта довольно плохая практика, так как в общем случае предупреждения должны быть вызваны действиями и логикой. И этот код должен жить в контроллерах.

Я предлагаю вам реорганизовать ваш текущий код, чтобы переместить логику, которая запускает предупреждение на правильный контроллер, а затем вы можете легко перейти на iOS 8, используя self в качестве контроллера.

Если вместо этого вы вызываете предупреждение из внешнего объекта, то передайте его контроллеру методу, вызывающему предупреждение. Где-то вверх по течению вы должны знать о контроллере.

Ответ 2

Сегодня я решил практически такую ​​же проблему. Как Jageen, я столкнулся с ситуацией, когда хотел представить UIAlertController, но из класса, отличного от UIViewController. В моем случае я хотел, чтобы появилось предупреждение, когда выполняется блок отказа HTTP-запроса.

Это то, что я использовал, и в отличие от нашего друга здесь, он отлично работал у меня.

UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(errorAlert, animated: true, completion: nil)

Ответ 3

Лучшее решение для классов UIView ниже

ObjectiveC

UIViewController *currentTopVC = [self currentTopViewController];
currentTopVC.presentViewController......... 

- (UIViewController *)currentTopViewController
{
    UIViewController *topVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
    while (topVC.presentedViewController)
    {
        topVC = topVC.presentedViewController;
    }
    return topVC;
}

Swift

var topVC = UIApplication.sharedApplication().keyWindow?.rootViewController
while((topVC!.presentedViewController) != nil){
     topVC = topVC!.presentedViewController
}
topVC?.presentViewController........

Ответ 4

Мое решение ниже:

Swift

class alert {
    func msg(message: String, title: String = "")
    {
        let alertView = UIAlertController(title: title, message: message, preferredStyle: .Alert)

        alertView.addAction(UIAlertAction(title: "Done", style: .Default, handler: nil))

        UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertView, animated: true, completion: nil)
    }
}

Вот пример использования:

let Alert = alert()
Alert.msg("My alert (without title)")
Alert.msg("This is my alert", title: "Warning!")

Ответ 5

У меня была ситуация, когда в subview есть кнопка, чтобы отклонить ее. Представляю предупреждение для подтверждения действия. Он отправляет сообщение делегату - который является контроллером представления, содержащим subview - для удаления subview

Первоначально я представил UIAlertView из UIView. Рефакторинг для UIAlertController, так как UIAlertController не может представить себя как UIAlertView can, я придумал следующее (в Swift, легко переведенное на ObjC):

Добавить протокол в подвью:

protocol MySubviewDelegate {

    // called when user taps subview/delete button
    //   or, you could call it from a gesture handler, etc.
    func displayAlert(alert : UIAlertController)

    // called when user confirms delete from the alert controller
    func shouldRemoveSubview(sender : AnyObject)

}

Добавьте делегата для подзаголовка и добавьте обработчик для нажатия кнопки/жестов:

class MySubview : UIView {

    var subviewDelegate : MySubviewDelegate!

    ...

    func handleTap(sender : AnyObject) {

        // set up the alert controller here
        var alert = UIAlertController(title: "Confirm Delete", 
            message: "This action is permanent. Do you wish to continue?", 
            preferredStyle: UIAlertControllerStyle.Alert)

        // Cancel action 
        //   nil handler means "no action if Cancel button selected"
        alert.addAction(UIAlertAction(title: "Cancel",
            style: UIAlertActionStyle.Cancel,
            handler: nil))

        // Confirm action
        alert.addAction(UIAlertAction(title: "Confirm",
            style: UIAlertActionStyle.Default,
            handler: { (action : UIAlertAction!) -> Void in

                // call delegate method to perform confirmed action, - i.e. remove
                self.subviewDelegate.shouldRemoveSubview(self)
        }))

        // call delegate method to display alert controller
        //   send alert object to delegate
        self.subviewDelegate.displayAlert(alert)
    }
}

Установите вызывающий UIViewController в качестве делегата subview, например, в свой метод viewDidLoad(), и включите методы протокола:

class viewController : UIViewController, MySubviewDelegate {

    override func viewDidLoad() {

        super.viewDidLoad()

        self.subviewDelegate = self

        ...
    }

    func displayAlert(alert : UIAlertController) {

        presentViewController(alert, animated: true, completion: nil)
    }

    func shouldRemoveSubview(sender : AnyObject) {

        // cast as UIView / MySubview subclass
        var subview = sender as MySubview

       // remove the subview / perform the desired action
       subview.removeFromSuperview()

       ...
    }

  ...
}

Это позволяет избежать необходимости находить самый верхний контроллер представлений или передавать ссылки на контроллеры представлений в subviews (кроме отношения к объекту/делегату).

Ответ 6

В Swift 3:

UIApplication.shared.keyWindow?.rootViewController?.present(alertView, animated: true, completion: nil)

Ответ 7

У меня была эта проблема. См. Мой SO ответ для кода, чтобы получить самый верхний контроллер представлений, с помощью которого можно представить другой контроллер представления.

Я согласен, что в большинстве случаев плохой практикой является представление контроллера представления из объекта, который не является контроллером представления, но иногда вам нужно.

Ответ 8

Для отображения UIAlertController в классе NSObject используйте код ниже.

    UIAlertController * popup =   [UIAlertController
                              alertControllerWithTitle:nil
                              message:nil
                              preferredStyle:UIAlertControllerStyleActionSheet];

    UIAlertAction* cancel = [UIAlertAction
                             actionWithTitle:@"Cancel"
                             style:UIAlertActionStyleCancel
                             handler:^(UIAlertAction * action) {
                                 [popup dismissViewControllerAnimated:YES completion:nil];
                             }];
    [popup addAction:cancel];

    UIViewController *rootViewController = [[Helper shareInstance] topViewController];
    [rootViewController presentViewController:popup animated:YES completion:nil];

//Поместите метод ниже в свой глобальный класс помощников.

- (UIViewController *)topViewController {
  return [self topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)topViewController:(UIViewController *)rootViewController {
    if (rootViewController.presentedViewController == nil) {
        return rootViewController;
    }

    if ([rootViewController.presentedViewController isMemberOfClass:[UINavigationController class]]) {
        UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
        UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
        return [self topViewController:lastViewController];
    }

    UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
    return [self topViewController:presentedViewController];
}

Ответ 9

В общем случае предупреждения должны обрабатываться в контроллере представления. Вот пример требуемого кода:

Swift 3

private func displayError(message: String) {
    let alertController = UIAlertController(title: nil, message: message, preferredStyle: .alert)
    let okayAction = UIAlertAction(title: "Okay", style: .default, handler: nil)
    alertController.addAction(okayAction)
    present(alertController, animated: true, completion: nil)
}