Как мне правильно использовать таймер для поэтапного добавления объектов в вложенное представление?

#ios #swift

#iOS #swift

Вопрос:

 class ViewController: UIViewController {

    let manImage = UIImage(named: "man.png")

    let buttons = (0..<5).map({_ in UIButton()})

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        createButtons()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func createButtons() {
        var pos = 25
        for index in 0...4 {
            delay(Double(arc4random_uniform(5))   5) {
                self.buttons[index].setBackgroundImage(self.manImage, forState: .Normal)
                self.buttons[index].translatesAutoresizingMaskIntoConstraints = false
                self.view.addSubview(self.buttons[index])
                self.view.addConstraint(NSLayoutConstraint(
                    item: self.buttons[index],
                    attribute: .Leading,
                    relatedBy: .Equal,
                    toItem: self.view,
                    attribute: .Leading,
                    multiplier: 1,
                    constant: CGFloat(pos)))
                pos  = 10
                }

        }
    }

    func delay(delay:Double, closure:()->()) {
        dispatch_after(
            dispatch_time(
                DISPATCH_TIME_NOW,
                Int64(delay * Double(NSEC_PER_SEC))
            ),
            dispatch_get_main_queue(), closure)
    }
}
  

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

delay(Double(arc4random_uniform(5)) 5)

разве это не означает задержку не менее 5 секунд между каждой итерацией цикла for? Почему он это делает?

Спасибо.

Ответ №1:

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

 func createButtons() {
    var delayTime = 0.0
    var pos = 25
    for index in 0...4 {
        delayTime = delayTime   Double(arc4random_uniform(5))   5
        delay(delayTime) {
            self.buttons[index].setBackgroundImage(self.manImage, forState: .Normal)
            self.buttons[index].translatesAutoresizingMaskIntoConstraints = false
            self.view.addSubview(self.buttons[index])
            self.view.addConstraint(NSLayoutConstraint(
                item: self.buttons[index],
                attribute: .Leading,
                relatedBy: .Equal,
                toItem: self.view,
                attribute: .Leading,
                multiplier: 1,
                constant: CGFloat(pos)))
            pos  = 10
        }
    }
}
  

Комментарии:

1. Что ж, это, безусловно, работает. Спасибо. Но есть ли причина, по которой мой исходный код иногда сбивался, а иногда нет?

2. Да, конечно! Ваш исходный код запускал все таймеры одновременно, каждый со случайной задержкой от 5 до 10 секунд … иногда они были разнесены, а иногда нет, просто случайно.

Ответ №2:

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

Возможно, вы захотите попробовать создать кнопку, затем отложить на случайное время, создать другую кнопку, затем снова отложить и т. Д. Разница в том, что вы должны создавать случайную задержку между созданием кнопок, а не создавать все четыре задержки одновременно. Для этого хорошо подойдет рекурсивная функция.

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

Комментарии:

1. Извините, вы правы. Моя тема неверна. Я это исправлю.