CAEmitterLayer, в конце концов, имеет задержку при добавлении EmitterCells

Мы наблюдали очень странную проблему (изображения ниже).

  1. У нас есть представленный контроллер представления с TeamBadgeView, который представляет собой кнопку, которая выдает эмодзи как CAEmitterCells.
  2. Нажатие этой кнопки позволяет пользователям спамить смайликами огня на своем экране.
  3. Закрытие представленного контроллера представления и повторное представление контроллера представления, и теперь есть задержка. Чем больше раз я представляю/отключаю контроллер представления, CAEmitterCell становится все более и более невосприимчивым
  4. Подтверждено, что это не проблема утечки, контроллер представления и кнопка освобождаются должным образом.
  5. Я пытался перемещать CAEmitterLayer и CAEmitterCell, удерживая ссылку на кнопке и объявляя локально, но аналогичные проблемы
  6. Возможно, самое странное, если я вообще не нажимаю кнопку, а просто много раз представляю/закрываю контроллер просмотра, а затем нажимаю кнопку, возникает задержка. Единственный раз, когда нет задержки, это нажатие кнопки при первом представлении контроллера представления.
  7. Я подтверждаю, что кнопка action срабатывает правильно, каждый раз, когда я спамлю кнопку. Просто ячейка эмиттера не рендерится несколько секунд. И некоторые ячейки-эмиттеры вообще не отображаются.

Дошло до ошеломляющей точки, есть ли у кого-нибудь какие-нибудь идеи или наводки на то, что это может быть?

Первая презентация ViewController:
введите здесь описание изображения

После 5-го представления ViewController (нажатие кнопки с той же скоростью):

введите здесь описание изображения

Код ViewController:

let teamBadgeView = TeamBadgeView.fromNib()
teamBadgeView.configure()

Код кнопки:

class TeamBadgeView: UIView {
    let emitter = CAEmitterLayer()
    let fireSize = CGSize(width: 16, height: 18)
    let fireScale: CGFloat = 0.8

    func configure() {
        emitter.seed = UInt32(CACurrentMediaTime())
        emitter.emitterPosition = CGPoint(x: bounds.midX, y: 0)
        emitter.emitterShape = CAEmitterLayerEmitterShape.line
        emitter.emitterSize = fireSize
        emitter.renderMode = CAEmitterLayerRenderMode.additive
        layer.addSublayer(emitter)
    }

    @IBAction func tapAction(_ sender: Any) {
        emitFire()
    }

    private func emitFire() {
        let cell = CAEmitterCell()
        let beginTime = CACurrentMediaTime()
        cell.birthRate = 1
        cell.beginTime = beginTime
        cell.duration = 1
        cell.lifetime = 1
        cell.velocity = 250
        cell.velocityRange = 50
        cell.yAcceleration = 100
        cell.alphaSpeed = -1.5
        cell.scale = fireScale
        cell.emissionRange = .pi/8
        cell.contents = NSAttributedString(string: "????").toImage(size: fireSize)?.cgImage

        emitter.emitterCells = [cell]
    }
}

person A O    schedule 12.12.2019    source источник
comment
Не могли бы вы выложить демонстрационный проект? Я хотел бы попробовать это.   -  person matt    schedule 12.12.2019
comment
Мэтт! рад вас видеть, уже много лет вы не появлялись в одной из моих тем :) позвольте мне создать проект прямо сейчас   -  person A O    schedule 12.12.2019
comment
Загружено здесь: github.com/MattyAyOh/FireDemo этот проект действительно кое-что показал: огонь на самом деле должен быть медленным! Похоже, что это никогда не должно было работать в первую очередь. В нашем ViewController мы используем переход героя (github.com/HeroTransitions/Hero), и он появляется этот переход каким-то образом заставляет огонь работать так, как ожидалось. При удалении перехода он снова стал медленным...   -  person A O    schedule 12.12.2019
comment
Ну, значит, я тебе не нужен!   -  person matt    schedule 12.12.2019
comment
Привет, поэтому я сделал свой собственный проект с кодом в вашем посте (а не в вашем демонстрационном проекте), и я заметил, что для отображения многих изображений огня мне пришлось добавить новую ячейку к emitterCells вместо того, чтобы установить ее в [cell] (и если emitterCells равен нулю, тогда мне пришлось сначала инициализировать его пустым массивом). Так может быть, это причина того, что это идет медленно?   -  person Tyler    schedule 12.12.2019
comment
нет, я знаю! Я делаю!   -  person A O    schedule 12.12.2019
comment
@matt, у нас все еще есть проблема, потому что мы не можем удалить переходы героев. Я сейчас много экспериментирую, так что могу просто держать вас в курсе, если вам интересно. TylerTheCompiler, это звучит интересно, позвольте мне попробовать это и в нашем производственном коде.   -  person A O    schedule 12.12.2019
comment
Да, я смог нажимать/выталкивать контроллер представления с помощью этого эмиттера, и он никогда не замедлялся и не имел задержки после того, как я внес это одно изменение.   -  person Tyler    schedule 12.12.2019
comment
Ок здорово! Я добавлю это как ответ тогда! Да, эти переходы героев, должно быть, вызывают какие-то дополнительные странности.   -  person Tyler    schedule 12.12.2019


Ответы (2)


Вместо того, чтобы каждый раз устанавливать массив emitterCells:

emitter.emitterCells = [cell]

... добавьте к нему новую ячейку. Обязательно инициализируйте его пустым массивом, если он равен нулю, иначе добавление не будет работать:

if emitter.emitterCells == nil {
    emitter.emitterCells = []
}

emitter.emitterCells?.append(cell)
person Tyler    schedule 12.12.2019

Благодаря @TylerTheCompiler мы смогли это понять, и это было действительно хромой.

Изменение одной строки, вместо установки emitterCells нам нужно было добавить

    emitter.emitterCells = [cell]

стал

    emitter.emitterCells?.append(cell)

Почему мы этого не заметили, так это то, что, похоже, происходит странное взаимодействие с переходами героев. Наш ViewController представлен через Hero Transition, и по какой-то причине в первый раз, когда он представлен, emitterCells = [cell] работает так, как ожидалось... но затем по какой-то причине, для каждого последующего Hero Transition к ViewController, ячейки начинают излучать все медленнее и медленнее, пока это не произойдет. обратно в ожидаемое медленное состояние. Невероятно странно, возможно баг в Герое, но кто его знает

person A O    schedule 12.12.2019