Не появляется Алерт

xcode
swift3

#1

Звучит банально, я много раз делал Алерт все отображалось, но тут не могу понять, почему не отображается?

Делал разными способами:

**Просто вставил в класс и запускал в методе viewDidLoad() :

class MainScreenTVC: UITableViewController {
  override func viewDidLoad() {
  super.viewDidLoad()
  newUpdatesAvailable()
 }
 
 override func newUpdatesAvailable() {
  let alert = UIAlertController(title: "Доступны обновления", message: "Вы хотите их скачать?", preferredStyle: .alert)
  let okAlertAction = UIAlertAction(title: "OK", style: .default) { (action : UIAlertAction) in
   if isInternetAvailable() {
    print("Internet connection OK")
    self.refreshData()
   } else {
    print("Internet connection FAILED")
    self.failedConnectionInternet()
   }
  }
  let cancelAlertAction = UIAlertAction(title: "Отмена", style: .cancel) { (action : UIAlertAction) in
   self.downLoadNewVersionButton.setTitle("Доступны обновления!", for: .normal)
  }
  alert.addAction(okAlertAction)
  alert.addAction(cancelAlertAction)
  present(alert, animated: true, completion: nil)
 }
}

Через extension

extension UIViewController {
	func newUpdatesAvailable() {
		let alert = UIAlertController(title: "Доступны обновления", message: "Вы хотите их скачать?", preferredStyle: .alert)
		let okAlertAction = UIAlertAction(title: "OK", style: .default) { (action : UIAlertAction) in
			let pathTorefreshData = UIApplication.shared.delegate as! MainScreenTVC
			if isInternetAvailable() {
				print("Internet connection OK")
				pathTorefreshData.refreshData()
			} else {
				print("Internet connection FAILED")
				pathTorefreshData.failedConnectionInternet()
			}
		}
		let cancelAlertAction = UIAlertAction(title: "Отмена", style: .cancel) { (action : UIAlertAction) in
			let pathTorefreshData = UIApplication.shared.delegate as! MainScreenTVC
			pathTorefreshData.downLoadNewVersionButton.setTitle("Доступны обновления!", for: .normal)
		}
		alert.addAction(okAlertAction)
		alert.addAction(cancelAlertAction)
		present(alert, animated: true, completion: nil)
	}
}

Создавал отдельный класс:

class AlertHelper {
    func showAlert(fromController controller: UIViewController) { 
        var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert)
        controller.presentViewController(alert, animated: true, completion: nil)
    }
}

Вызывал

 var alert = AlertHelper()
 alert.showAlert(fromController: self)

Появляется одна и даже ошибка

Warning: Attempt to present <UIAlertController: 0x7fe4a2d24130> on <rusPddRules.MainScreenTVC: 0x7fe4a2d195b0> whose view is not in the window hierarchy!

Из ошибки понятно, что неправильная иерархия, но куда тут не правильная. хз


Вопрос про переход между контроллерами при проверке условия в методе viewDidLoad()
#2

Попробуйте так:

override func viewDidLoad() {
    super.viewDidLoad()
    DispatchQueue.main.async {
        let alert = UIAlertController(title: "abc", message: "def", preferredStyle: .alert)
        self.present(alert, animated: true)
    }
}

#3

Да, так Алерт запускается и нету ошибки. А в чем причина была? Расскажите!


#4

вот в этом (20 символов)


#5

Это решение, а не причина)

Причина была в том, что вы пытались отобразить алерт во viewDidLoad, но т.к., сцена еще не отобразилась, ваш алерт не отображался.


#6

это было объяснение, что вызывать алерт нужно в главном потоке!


#7

А в каком?


#8

Затупил, исправился.


#9

Такое сложно объяснить, что то вроде этого:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "A", message: "B", preferredStyle: .alert)
            
            let vc = ViewController2()
            vc.view.layoutIfNeeded() // Вызывает viewDidLoad в ViewController2
            
            vc.present(alert, animated: true) // В ViewController2 вызываете present хотя контроллер еще не готов
            
            self.addChildViewController(vc)
            vc.didMove(toParentViewController: self)
            self.view.addSubview(vc.view)
        }
    }
}
class ViewController2: UIViewController {}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.main.async {
            let alert = UIAlertController(title: "A", message: "B", preferredStyle: .alert)
            
            let vc = ViewController2()
            vc.view.layoutIfNeeded()
            DispatchQueue.main.async {
                vc.present(alert, animated: true) // Если вызвать асинхронно и дождаться пока освободится очередь (отработает то что ниже), то всё ок
            }
            
            self.addChildViewController(vc)
            vc.didMove(toParentViewController: self)
            self.view.addSubview(vc.view)
        }
    }
}

#10

Ага, примерно понял. Спасибо за пример!

Спасибо ребята!!!