2016-10-12 2 views
0

У меня проблема с функциями таймера. Я запускаю таймер, когда нажимаю на btn (startBtn), и я показываю новый элемент управления представлением в качестве popover при ударе другого btn (restBtn) Теперь он правильно запускает таймер и открывает новый диспетчер представлений как popover с подсчетом времени вниз.Запустить таймер в другом диспетчере просмотра в swift

Проблема в том, когда в новом диспетчере просмотра он достигает 0 и отклоняется от себя. Он должен автоматически запускать таймер в первом режиме управления представлением.

Вот мой код на mainVC:

var timeLeft = 0 
var myTimer: Timer! 


@IBAction func startBtnPressed(_ sender: AnyObject) { 
     timeLeft = 0 
     myTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(workoutStartVC.timerRunning), userInfo: nil, repeats: true) 
    } 


@IBAction func restBtnPressed(_ sender: AnyObject) { 
     print("rest mode button is pressed and i am showing a overlay right now with data count down") 
     myTimer.invalidate() 

     // show popup when user interacts with restbtn 
     let popOpVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUpID") as! PopUpVC 
     self.addChildViewController(popOpVC) 
     popOpVC.view.frame = self.view.frame 
     popOpVC.view.backgroundColor = BLUE_COLOR.withAlphaComponent(0.75) 
     self.view.addSubview(popOpVC.view) 
     popOpVC.didMove(toParentViewController: self) 

     timeLbl.text = "" 
    } 

func timerRunning() { 
     timeLeft = timeLeft + 1 
     print("the timeLeft is: \(timeLeft)") 

     **timeLbl.text = "\(timeLeft)"** (HERE I AM GETTING ON THE SECOND TIME WHEN DISMISSING THE POPUPVC A FOUND NILL) 

     if timeLeft == 30 { 
      myTimer.invalidate() 
      timeLbl.text = "" 
     } 
    } 

Вот мой код на PopUpVC:

var timeLeft = 0 
    var myTimer: Timer! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     timeLeft = 10 
     myTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(PopUpVC.timerRunning), userInfo: nil, repeats: true) 
    } 


    func timerRunning() { 
     timeLeft = timeLeft - 1 
     restModeTimer.text = "\(timeLeft)" 

     if timeLeft == 0 { 
      myTimer.invalidate() 
      restModeTimer.text = "" 
      self.view.removeFromSuperview() 

      let worskoutStartVC = workoutStartVC() 
      worskoutStartVC.myTimer = nil 
      worskoutStartVC.timeLeft = 0 

      worskoutStartVC.myTimer = Timer.scheduledTimer(timeInterval: 1.0, target: worskoutStartVC, selector: #selector(worskoutStartVC.timerRunning), userInfo: nil, repeats: true) 
     } 
    } 

Может кто-нибудь объясняет, почему я получаю нашел ноль в то время как разворачивание вариант значение в той части, которую я сделал полужирным в моем коде ниже?

спасибо!

ответ

1

Из того, что я вижу, это, кажется, как вы инициализации нового View Controller ... в строке:

let worskoutStartVC = workoutStartVC() 

Так что, когда это будет создаваться, выход на этикетке не подключен в так же, как если бы представление было инициализировано из раскадровки.

Так что я вижу 2 вещи, которые вы можете попробовать:

  1. (Возможно, лучший вариант) Передайте ссылку на оригинальный контроллер представления ко второму контроллеру представления, так что вы не имеете чтобы создать его снова. И затем вы используете эту ссылку для воссоздания таймера. Поскольку то, что вы делаете сейчас, по существу создает новый контроллер просмотра каждый раз, когда таймер PopUpVC заканчивается. Подробнее в конце поста

  2. (Это приведет к нескольким копиям исходного VC, так это больше для помощи понять, что происходит) Вы можете создать еще одну копию контроллера представления с использованием UIStoryboard (), как вы делали в приведенном выше коде, и что должен правильно подключаться к розетке.

Как ваш код говорит:

// show popup when user interacts with restbtn 
    let popOpVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUpID") as! PopUpVC 
    self.addChildViewController(popOpVC) 

Опять же, вариант 1 ИМО лучший выбор, хотя вероятны и другие структуры, чтобы рассмотреть. И причина, по которой метка равна нулю, заключается в том, что она не связана с объектом метки при создании представления с помощью workoutStartVC().

EDIT: Добавить информацию о том, как передать в ссылке:

Код PopUpVC может измениться к иметь ссылку на оригинальный ВК:

var timeLeft = 0 
var myTimer: Timer! 
var parentVC: workoutStartVC? 

override func viewDidLoad() { 
    super.viewDidLoad() 

    timeLeft = 10 
    myTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(PopUpVC.timerRunning), userInfo: nil, repeats: true) 
} 


func timerRunning() { 
    timeLeft = timeLeft - 1 
    restModeTimer.text = "\(timeLeft)" 

    if timeLeft == 0 { 
     myTimer.invalidate() 
     restModeTimer.text = "" 
     self.view.removeFromSuperview() 

     if let worskoutStartVC = workoutStartVC { 
      worskoutStartVC.myTimer = nil 
      worskoutStartVC.timeLeft = 0 

      worskoutStartVC.myTimer = Timer.scheduledTimer(timeInterval: 1.0, target: worskoutStartVC, selector: #selector(worskoutStartVC.timerRunning), userInfo: nil, repeats: true) 
     } 
    } 
} 

И вы должны установить это свойство при переходе в этой точке зрения: (Фрагмент)

 // show popup when user interacts with restbtn 
     let popOpVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "sbPopUpID") as! PopUpVC 
     self.addChildViewController(popOpVC) 
     popOpVC.parentVC = self 
     popOpVC.view.frame = self.view.frame 
     popOpVC.view.backgroundColor = BLUE_COLOR.withAlphaComponent(0.75) 
     self.view.addSubview(popOpVC.view) 
     popOpVC.didMove(toParentViewController: self) 

ПРИМЕЧАНИЕ: Пробовал мое самое лучшее к объявлению просто имена классов, которые я предполагаю, что они из вашего кода, но некоторые вещи, возможно, придется отрегулировать.

+1

1000000 указывает на этого парня –

0

Проблема заключается в том, что timeLbl предположительно является неявным образом развернутым дополнительным, который неожиданно равен нулю после того, как контроллер представления, которому принадлежит его, был выпущен. Вы должны аннулировать таймер, когда вы отклоняете popover, вызывая на нем invalidate(), так что обратный вызов таймера не попадает после того, как он не предполагается.

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

+0

Я сделал недействительным таймер при ударе 0. –

+0

Я добавил timeLbl к timelbl? и теперь он подсчитывается, но он не помещает его в timeLbl.text. –

+0

. Вы не аннулируете таймер в ответ на отклонение диспетчера представлений - после этого 'timeLbl' будет равен нулю из-за выгрузки Nib, установив его на нуль. У вас есть повторяющийся таймер с периодичностью 1, а после 30 повторений вы его недействительны. Если вы отключите контроллер вида в любое время до этого, произойдет сбой. – mz2

Смежные вопросы