Медленная загрузка пользовательского UIView в Swift

Фон

Чтобы создать текстовое представление с горизонтальной прокруткой для вертикальный монгольский шрифт, я создал собственный подкласс UIView. Класс берет UITextView, помещает его в UIView, поворачивает и переворачивает этот вид, а затем помещает этот вид в родительский UIView.

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

Цель поворота и отражения состоит в том, чтобы текст был вертикальным и чтобы перенос строк работал правильно. Цель вставить все в родительский элемент UIView состоит в том, чтобы автоматический макет работал в раскадровке. (Подробнее см. здесь.)

Код

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

import UIKit

@IBDesignable class UIMongolTextView: UIView {

    private var view = UITextView()
    private var oldWidth: CGFloat = 0
    private var oldHeight: CGFloat = 0

    @IBInspectable var text: String {
        get {
            return view.text
        }
        set {
            view.text = newValue
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect){
        super.init(frame: frame)
    }

    override func sizeThatFits(size: CGSize) -> CGSize {
        // swap the length and width coming in and going out
        let fitSize = view.sizeThatFits(CGSize(width: size.height, height: size.width))
        return CGSize(width: fitSize.height, height: fitSize.width)
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // layoutSubviews gets called multiple times, only need it once
        if self.frame.height == oldHeight && self.frame.width == oldWidth {
            return
        } else {
            oldWidth = self.frame.width
            oldHeight = self.frame.height
        }

        // Remove the old rotation view
        if self.subviews.count > 0 {
            self.subviews[0].removeFromSuperview()
        }

        // setup rotationView container
        let rotationView = UIView()
        rotationView.frame = CGRect(origin: CGPointZero, size: CGSize(width: self.bounds.height, height: self.bounds.width))
        rotationView.userInteractionEnabled = true
        self.addSubview(rotationView)

        // transform rotationView (so that it covers the same frame as self)
        rotationView.transform = translateRotateFlip()

        // add view
        view.frame = rotationView.bounds
        rotationView.addSubview(view)

    }

    func translateRotateFlip() -> CGAffineTransform {

        var transform = CGAffineTransformIdentity

        // translate to new center
        transform = CGAffineTransformTranslate(transform, (self.bounds.width / 2)-(self.bounds.height / 2), (self.bounds.height / 2)-(self.bounds.width / 2))
        // rotate counterclockwise around center
        transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
        // flip vertically
        transform = CGAffineTransformScale(transform, -1, 1)

        return transform
    }

}

Проблема

Я заметил, что пользовательское представление загружается очень медленно. Я новичок в Xcode Instruments, поэтому посмотрел полезные видеоролики Отладка проблем с памятью с помощью Xcode и Profiler и Профилировщик времени.

После этого я попытался найти проблему в своем собственном проекте. Кажется, что независимо от того, использую ли я инструменты Time Profiler, Leaks или Allocations, все они показывают, что мой метод класса init выполняет слишком много работы. (Но я как бы знал это уже из-за медленной загрузки раньше.) Вот снимок экрана из инструмента «Распределения»:

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

Я не стал расширять все дерево вызовов, потому что оно не поместилось бы. Почему создается так много объектов? Когда я создал трехслойный пользовательский вид, я знал, что он не идеален, но количество слоев, которые появляются из дерева вызовов, смехотворно. Что я делаю не так?


person Suragch    schedule 07.12.2015    source источник
comment
У меня такая же ситуация. Я ожидаю решения вышеуказанной проблемы.   -  person shunsuke_stackoverflow    schedule 07.12.2015
comment
Моя медленная точка - это «super.init (coder: aDecoder)» в «required init? (coder aDecoder: NSCoder)».   -  person shunsuke_stackoverflow    schedule 07.12.2015


Ответы (1)


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

Создайте свое подпредставление при создании своего представления, а затем только отрегулируйте его положение в layoutSubviews, а не удаляйте и повторно добавляйте его.

person jcaron    schedule 07.12.2015
comment
Я нарушил это правило в крайнем случае вместе с кодом, который гарантирует, что оно добавляется только один раз. - person Peter DeWeese; 07.12.2015
comment
Пытаясь последовать вашему совету, я вырезал весь код в методе layoutSubviews, но все равно получал аналогичную задержку. Я задал новый вопрос для Это. Пожалуйста, дайте мне знать, если у вас есть какие-либо мысли. - person Suragch; 11.12.2015