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

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

Я настроил свой тестовый проект с двумя контроллерами представления. Кнопка на первом контроллере представления вызывает переход шоу ко второму контроллеру представления. На втором контроллере представления есть мое собственное представление. (Использование второго контроллера представления позволило мне понять, сколько времени ушло на загрузку пользовательского представления.)

Пользовательский код просмотра:

import UIKit

@IBDesignable class UIMongolTextView: UIView {

    var textView = UITextView() // key line

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

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

Как видите, единственное отличие от UIView в том, что я добавил свойство UITextView. И именно этот пользовательский вид загружается очень медленно. Запустив инструмент «Распределения» в «Инструментах», я получаю следующие результаты (количество 997):

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

Однако, если я закомментирую строку

    //var textView = UITextView()

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

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

Что здесь происходит? Можно ли использовать свойство UITextView в пользовательском представлении и избежать медленной загрузки?


person Suragch    schedule 10.12.2015    source источник
comment
У меня та же проблема, но я использую UIPageViewController, и при попытке перейти на следующую страницу возникает задержка, потому что для запуска текстового представления требуется время.   -  person Jacob    schedule 17.12.2015
comment
Примечание для себя (попробовать позже): что, если я объявлю его как UIView, а затем приведу его к UITextView позже?   -  person Suragch    schedule 11.05.2016


Ответы (4)


Пробовал что-то подобное, когда метка и текстовое поле были добавлены в качестве подвидов в подкласс uiview. Я сделал следующее:

@interface CustomTextField : UIView

@property (weak, nonatomic) IBOutlet UITextField *valueField;

@end

Итак, у нас был xib-файл, в который мы фактически добавили метку и текстовое поле. В файле xib владельцем файла является «CustomTextField», а выходы связаны с файлом заголовка оттуда.

Метод конструктора выглядит так:

- (id)initWithValue:(NSString *)value
{
    self = [super initWithFrame:CGRectZero];
    if (self) {
        NSArray *nibs = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
        UIView *view = nibs[0];
        self.valueField.frame = view.bounds;
        [self setFrame:view.bounds];
        [self addSubview:view];
        [self.valueField setText:value];
    }

    return self;
}

У меня работает нормально.

person Anand    schedule 19.12.2015
comment
Поместив UITextView в xib, а затем загрузив xib (согласно этому ответу) и сняв флажок selectable, вы избавились от длительной задержки для моего надуманного примера в моем вопросе (но получая мой исходный вид правильно повернуть с xib еще не получилось). Во всяком случае, это одно из решений моего вопроса здесь. - person Suragch; 30.12.2015

Узким местом является свойство selectable вашего UITextView. Существует необъяснимая проблема с производительностью при создании UITextView с selectable, установленным в значение по умолчанию true.

Самый простой способ обойти эту проблему — добавить текстовое представление с помощью раскадровки, убедившись, что вы сняли флажок со свойства selectable. Похоже, не существует задокументированного способа создания недоступного для выбора текстового представления в коде (поскольку установка для выбора значения false после создания не позволяет избежать проблемы с производительностью во время создания). Если вам нужно выбираемое текстовое представление, сначала создайте невыбираемое текстовое представление, а затем установите для выбираемого значение true в viewDidAppear.

Если вы не можете использовать раскадровку, вы можете рассмотреть возможность использования стороннего класса, такого как TTTAttributedLabel.

Похоже, что Apple использует частный API, чтобы избежать этой проблемы. Другие предприимчивые разработчики обнаружили, что в ChatKit текстовые представления создаются с использованием закрытого метода. называется initReadonlyAndUnselectableWithFrame:textContainer:.

person jamesk    schedule 19.12.2015
comment
Это не тот ответ, на который я надеялся, но он отвечает на вопрос (в некоторой степени), почему это происходит. - person Suragch; 19.12.2015
comment
Вы должны иметь возможность делать все, что вам нужно, с помощью пользовательского контроллера представления, который поставляется со своим собственным свойством view и к которому вы можете добавить пользовательское свойство textView, связанное с UITextView в вашей раскадровке. Если вы не хотите, чтобы представление было полноэкранным, используйте объект Container View в своей раскадровке, чтобы ограничить настраиваемый контроллер представления определенной областью. Затем примените все необходимые преобразования к представлению в viewDidLayoutSubviews (для внешнего вида по умолчанию) и viewWillTransitionToSize:withTransitionCoordinator (для изменения ориентации). - person jamesk; 20.12.2015
comment
Отличный ответ. Это также относится к свойству «enabled» UITextField. - person Trevor Panhorst; 20.04.2016
comment
Просто примечание: замедление происходит только при отладке. Если вы запустите приложение вручную, задержки не будет. - person Kevin; 25.05.2016
comment
Мои два цента: кажется, что UITextField выполняет некоторые фоновые задачи и должен дождаться их завершения (что-то вроде waitUntilDone), чтобы установить selectable в true. Поскольку установка selectable на true сразу после загрузки UITextField в любом случае вызывает зависание. И даже через секунду после этого. Но если я попытаюсь установить его через несколько секунд, он будет установлен мгновенно. Итак, в сеттере selectable есть что-то вроде waitUntilBackgroundTasksAreComplete. - person FreeNickname; 08.09.2016
comment
Куда смотрит яблоко? - person Nik Kov; 21.10.2016

загрузил ваш код с github, почему бы вам просто не написать подкласс UITextView вместо UIView?

//
//  UIMongolTextView-A.swift
//  Mongol App Componants
//
//  Created by Allen Zhang on 12/13/15.
//  Copyright © 2015 MongolSuragch. All rights reserved.
//

import UIKit

class UIMongolTextView_A: UITextView {

    override func awakeFromNib() {
        super.awakeFromNib()
        self.setup()
    }

    func setup() {
        // 1-10: ᠨᠢᠭᠡ ᠬᠤᠶᠠᠷ ᠭᠤᠷᠪᠠ ᠳᠦᠷᠪᠡ ᠲᠠᠪᠤ ᠵᠢᠷᠭᠤᠭ᠎ᠠ ᠳᠤᠯᠤᠭ᠎ᠠ ᠨᠠᠢ᠌ᠮᠠ ᠶᠢᠰᠦ ᠠᠷᠪᠠ

        self.transform = translateRotateFlip()


    }

    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func drawRect(rect: CGRect) {
        // Drawing code
    }
    */
    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
    }
}
person Allen    schedule 13.12.2015
comment
Первоначально это то, что я пытался сделать (поскольку это то, что я сделал для Android). Проблема в том, что вращение UITextView искажает как текст, так и автоматический макет. Дополнительные сведения см. в этом вопросе. Тем не менее, я ценю, что вы приложили усилия для загрузки проекта. - person Suragch; 14.12.2015

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

У меня был UITextView со статическим текстом на раскадровке. Его нельзя было отредактировать или выбрать. На медленном iPod Touch загрузка ViewController займет 5 секунд.

Оказывается, у меня был смайлик в статичном тексте. Когда я удалил смайлик, проблема исчезла! Я использовал инструменты, чтобы разобраться в том, что происходит, и примерно на 25 уровнях в глубине трассировки он попадал в кучу… шрифтов… методов. Я использовал системный шрифт без атрибутов, поэтому первой мыслью, которая пришла мне в голову, был символ эмодзи в моем тексте.

person Chad Pavliska    schedule 13.10.2016