Подожди 50 тиков цикла в iOS - PullRequest
2 голосов
/ 27 мая 2019

Я бы хотел дождаться запуска цикла выполнения и отображения экрана 50 раз перед выполнением операции.

Нужно ли использовать CAMediaTiming и счетчик для этого? Есть ли способ подключиться к NSRunLoop напрямую? Можно ли добиться этого, используя 50 вложенных DispatchQueue.async вызовов, например, так?

import Dispatch

func wait(ticks: UInt, queue: DispatchQueue = DispatchQueue.main, _ handler: @escaping () -> Void) {
    var ticks = ticks

    func predicate() {
        queue.async {
            ticks -= 1
            if ticks < 1 {
                handler()
                return
            }
            queue.async(execute: predicate)
        }
    }

    predicate()
}

РЕДАКТИРОВАТЬ: если кому-то интересно, фрагмент работает и работает очень хорошо, когда мы говорим о цикле запуска приложений.

Ответы [ 2 ]

2 голосов
/ 27 мая 2019

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

let displayLink = CADisplayLink(target: self, selector: #selector(drawFunction(displayLink:)))
displayLink.add(to: .main, forMode: .commonModes)

В drawFunction (или предикате и т. Д.) Мы можем вычесть тики. Когда они достигают 0, мы достигли 50-го кадра и аннулируем displayLink.

var ticks = 50
@objc private func drawFunction(displayLink: CADisplayLink) {
    doSomething()
    ticks -= 1
    if ticks == 0 {
        displayLink.invalidate()
        displayLink = nil
        return
    }
}

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

Свойство duration обеспечивает интервал времени между кадрами в MaximumFramesPerSecond. Чтобы вычислить фактическую продолжительность кадра, используйте targetTimestamp - timestamp. Вы можете использовать это значение в своем приложении для расчета частоты кадров дисплея, приблизительного времени, в течение которого будет отображаться следующий кадр, и для настройки поведения при рисовании так, чтобы следующий кадр был подготовлен вовремя для отображения.

0 голосов
/ 27 мая 2019

Я думаю, что лучшее решение использовать CADisplayLink вместо Dispatch.Вот пример:

    class Waiter {
        let handler: () -> Void
        let ticksLimit: UInt
        var ticks: UInt = 0
        var displayLink: CADisplayLink?

        init(ticks: UInt, handler: @escaping () -> Void) {
            self.handler = handler
            self.ticksLimit = ticks
        }

        func wait() {
            createDisplayLink()
        }

        private func createDisplayLink() {
            displayLink = CADisplayLink(target: self,
                                      selector: #selector(step))
            displayLink?.add(to: .current,
                        forMode: RunLoop.Mode.default)
        }

        @objc private func step(displaylink: CADisplayLink) {
            print(ticks)
            if ticks >= ticksLimit {
                displayLink?.invalidate()
                handler()
            }
            ticks += 1
        }
    }

Вот пример использования:

    let waiter = Waiter(ticks: 50) {
        print("Handled")
    }
    waiter.wait()
...