Временной интервал в цикле for in

swift

#1

Делаю итерацию по массиву и вывожу текст построчно в textView. Каким образом можно задать интервал отображения строки? Визуально должно выглядить, как чат. Сейчас получается ерунда… )

let timerTwoSec = (Int64(NSEC_PER_SEC) * 2) // 2 секунды пауза.

override func viewDidLoad() {
    super.viewDidLoad()
    
        if answer.count == 0 {
            var a = ""
            for i in array.storyOneText1 {
                a += "\(i)\n\n"
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timerTwoSec), dispatch_get_main_queue(), { () -> Void in
                    textView.text = a
                })
            }
            
}

#2

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

override func viewDidLoad() {
    super.viewDidLoad()
    NSOperationQueue().addOperationWithBlock {
        for i in 0..<10 {
            NSOperationQueue.mainQueue().addOperationWithBlock {
                self.textView.text = "\(i)"
            }
            NSThread.sleepForTimeInterval(2)
        }
    }
}

#3

Спасибо, но Ваш способ работает аналогично моему - отображаются сразу все строки с задержкой… (


#4
override func viewDidLoad() {
    super.viewDidLoad()
    let items = ["AAA", "BBB", "CCC"]
    NSOperationQueue().addOperationWithBlock {
        for item in items {
            NSOperationQueue.mainQueue().addOperationWithBlock {
                self.textView.text! += item + "\n"
            }
            NSThread.sleepForTimeInterval(2)
        }
    }
}

#5

Ваш чат легко решается таймером:

class ViewController: UIViewController {

    let text = ["Вася: Привет!","Катя: Привет)","Вася: Как дела?","Катя: Хорошо. Как ты?","Вася: Скучаю...","Катя: Пойдем в кино)))"]

    var timer = NSTimer()
    var timeInterval = 2.0
    var index = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        timer = NSTimer.scheduledTimerWithTimeInterval(timeInterval, target: self, selector: #selector(showMessage), userInfo: nil, repeats: true)
    }

    func showMessage() {
        if index >= text.count {
            timer.invalidate()
            return
        }
        print(text[index])
        index += 1
    }
}

Можете запускать таймер без повтора и активировать его снова с другим временным интервалом, все что угодно, главное не забывайте останавливать таймер, если он не нужен или при переходах на другие контроллеры, потому что тикать он будет исправно ))


Modal View Controllers в цикле
#6

Спасибо! Теперь все работает. )


#7

Спасибо за решение, очень помогаете! )


#8

Дайте ссылку, где почитать о конструкции с решеткой.


#11

Если коротко, то это довольно свежее новшество в Swift:
Раньше использовался старый способ в виде Selector = "method", который мог содержать ошибки, например, вы могли переименовать какой-то метод а селектор не поменять. В результате, ошибка вылазила уже в runtime, причем не всегда сразу.

Теперь же вы используете команду #selector и указатель на ваш метод. Убивается сразу 2 зайца - Xсode автоматически проверяет на существование указанного метода и не дает компилировать, если он не существует.


#12

После долгих проб и ошибок понял, что данное решение не идеально. Допустим, мы захотим расширить функционал. Если цикл заключить в конструкцию if, то он начнет вылазить за свои границы. Мне нужно, что-бы цикл отработал, вывел построчно текст и потом в конструкции if сработал код отображения label. Сейчас же цикл отрабатывает и одновременно отображает label


#13

Тогда вам и вправду лучше использовать NSTimer и с ним уже что то придумывать.


#14

С ним тоже возникают проблемы в цикле. Вот создал такую конструкцию:

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

Добавляю функционал в свой цикл:

for i in array.storyOneText1 {
                     delay(3) {
                         self.day1 += "\(i)\n\n"
                         self.textView.text = self.day1
                     }
                 }

И все равно отображается исключительно все с задержкой, хотя по логике, с задержкой должна отображаться каждая обработанная строка в цикле. Может я где-то туплю? Подскажите, пожалуйста, что-то совсем не получается.

Рассмотренный выше DenisDev вариант с селектором кажется мне слишком объемным.


#15

После долгих странствий вернулся к Вашему решению. Разобрался в нем и понял, что оно самое удобное в данный момент. Спасибо! )


#16

Отлично, самое лучшее это разобраться и… написать свое )) главное не забывайте отключать таймеры!


#17

Появилась еще одна проблемка… Захотел расширить showMessage, что-бы она могла принимать любой массив, и его обрабатывать. Но возникли проблемы с селектором, он отказывается принимать функцию с входными значениями.


#18

Не стремитесь к универсальности - лучше несколько узкоспециализированных методов. Но если если все-таки нужна универсальность, то обязательно решайте вопрос с index, не забывайте вместе с массивом и индекс передавать.

По поводу селектора - все что угодно можете передавать через userInfo. По своей сути, это словарь (ключ-значение). Например надо передать индекс:
userInfo: ["idx":index]
НО! Это значение будет передано ТОЛЬКО один раз, в момент инициализации таймера.
То есть вам надо убрать повтор вызова таймера reteat: false и каждый раз создавать таймер заново.

Вытащить данные из userInfo тоже легко:

func showMessage(info: NSNotification) {
        let userInfo = info.userInfo!
        let idx = userInfo["idx"] as! Int
        ...

#19

Спасибо за столь емкий ответ, очень помогаете.