(UILabel) nil, Невозможно вставить текст в метку

Добрый день,

У меня, кажется, такая простая проблема, но я просто не могу обдумать ее.

У меня есть представление контейнера внутри контроллера представления. В этом контейнере у меня мало этикеток. Контейнер имеет собственный контроллер представления. В контроллере представления для контейнера у меня работает таймер, и я хочу, чтобы эта метка показывала таймер. Но каждый раз, когда я использую этот ярлык, приложение вылетает с ошибкой «Поток 1: Неустранимая ошибка: неожиданно найден ноль при развертывании необязательного значения».

Если я прокомментирую строку с этой меткой, все будет работать нормально.

    @IBOutlet weak var timeLabel: UILabel!

var counter = 0.0
var timer = Timer()
var isRunning = false


func startStopTimer () {
    if isRunning {
        timer.invalidate()
        isRunning = false
    }else {
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
        isRunning = true
    }
}

@objc func updateTimer() {
    counter = counter + 0.1

    timeLabel.text = String(counter) 
}

Это первый раз, когда я играю с представлением контейнера в основной раскадровке.

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

Спасибо, Джонас.


Полный код

    class MainViewController: UIViewController {
@IBOutlet weak var topContainer: UIView!
@IBOutlet weak var informationContainer: UIView!

@IBOutlet weak var startStopButtonOutlet: UIButton!

let informationContainerVC = InformationContainerViewController()

override func viewDidLoad() {
    super.viewDidLoad()

    setupView()
}

func setupView() {
    topContainer.layer.cornerRadius = 5
    topContainer.layer.masksToBounds = true

    informationContainer.layer.cornerRadius = 5
    informationContainer.layer.masksToBounds = true

    startStopButtonOutlet.layer.cornerRadius = 5
    startStopButtonOutlet.layer.masksToBounds = true
}

@IBAction func startStopButton_TouchUpInside(_ sender: UIButton) {
    informationContainerVC.startStopTimer()

    UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
        sender.transform = CGAffineTransform.identity

    }, completion: nil)

    if informationContainerVC.isRunning {
        startStopButtonOutlet.setTitle("Push to Pause", for: .normal)
    }else {
        startStopButtonOutlet.setTitle("Push to Start", for: .normal)
    }
}

@IBAction func startStopButton_TouchDown(_ sender: UIButton) {
    UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseIn], animations: {
        sender.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)

        if self.informationContainerVC.isRunning {

            sender.backgroundColor = UIColor.white.withAlphaComponent(0.5)
        }else {
            sender.backgroundColor = UIColor.green.withAlphaComponent(0.8)
        }



    }, completion: nil)
}

@IBAction func startStopButton_TouchUpOutside(_ sender: UIButton) {
    UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
        sender.transform = CGAffineTransform.identity

    }, completion: nil)
}
}

Вот код для контроллера представления контейнера

class InformationContainerViewController: UIViewController {

@IBOutlet weak var timeLabel: UILabel!

var counter = 0.0
var timer = Timer()
var isRunning = false


func startStopTimer () {
    if isRunning {
        timer.invalidate()
        isRunning = false
    }else {
        timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
        isRunning = true
    }
}

@objc func updateTimer() {
    counter = counter + 0.1

    timeLabel.text = String(counter)

}
}

person Jónas Rafnsson    schedule 26.08.2018    source источник
comment
Проверьте, подключена ли розетка к раскадровке.   -  person Rakesha Shastri    schedule 26.08.2018
comment
Он подключен к правильной метке.   -  person Jónas Rafnsson    schedule 26.08.2018
comment
Когда вызывается startStopTimer?   -  person Rakesha Shastri    schedule 26.08.2018
comment
startStopTimer вызывается с помощью кнопки на mainViewController. Этот контейнер находится на том же контроллере представления, что и кнопка.   -  person Jónas Rafnsson    schedule 26.08.2018
comment
Возможно, вы захотите поделиться полным кодом обоих ваших классов.   -  person Rakesha Shastri    schedule 26.08.2018
comment
Убедитесь, что вы подключили розетку к правильному контроллеру просмотра. если метка находится в viewcontroller A, она должна быть подключена к VC_A   -  person Lal Krishna    schedule 26.08.2018
comment
Я считаю, что это связано с правильным VC. Я разместил весь код.   -  person Jónas Rafnsson    schedule 26.08.2018
comment
Контроллер представления информации не загружен. Таким образом, розетка никогда не подключена. У вас должен быть переход или код для отправки или представления контроллера представления из первого контроллера представления. Не создавайте новый экземпляр внутри класса и просто вызывайте его. Когда вы хотите, чтобы контроллер информационного представления появлялся и вызывал таймер?   -  person Rakesha Shastri    schedule 26.08.2018
comment
Я хочу, чтобы контейнер визуализировался одновременно с основным VC. Я просто использовал представление контейнера, чтобы было проще регулировать размер всего внутри него между устройствами. Но я бы хотел, чтобы таймер запускался, как только вы нажмете кнопку startStopButton.   -  person Jónas Rafnsson    schedule 26.08.2018
comment
Насколько я понял, вам не нужен второй контроллер просмотра. Просто скройте и покажите контейнер по мере необходимости в том же контроллере представления.   -  person Rakesha Shastri    schedule 26.08.2018


Ответы (1)


Когда вы говорите let informationContainerVC = InformationContainerViewController(), вы создаете новый экземпляр InformationContainerViewController, который не связан с раскадровкой, поэтому ни один из выходов не установлен.

Вам нужно получить ссылку на экземпляр контроллера представления, который фактически находится в вашем представлении контейнера. Вы можете сделать это в prepare(for segue:); Если вы посмотрите на свою раскадровку, вы увидите, что есть переход, который связывает ваш содержащий контроллер представления с содержащимся контроллером представления.

В вашем MainViewController:

var informationContainerVC: InformationContainerViewController?

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if let destVC = segue.destination as? InformationContainerViewController {
        self.informationContainerVC = destVC
    }
}

@IBAction func startStopButton_TouchUpInside(_ sender: UIButton) {
    informationContainerVC?.startStopTimer()

    UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
        sender.transform = CGAffineTransform.identity

    }, completion: nil)

    if informationContainerVC?.isRunning {
        startStopButtonOutlet.setTitle("Push to Pause", for: .normal)
    } else {
        startStopButtonOutlet.setTitle("Push to Start", for: .normal)
    }
}

Теперь у вас будет ссылка на правильный экземпляр контроллера представления.

person Paulw11    schedule 26.08.2018