Avatar ·

После обновления Xcode до 11.2 приложение падает с ошибкой _UITextLayoutView при использовании UITextView

Всем привет! Столкнулся с проблемой после обновления Xcode с 11.1 на 11.2. Приложение, которое отлично работало раньше, теперь вылетает при запуске с крашем, связанным с `UITextView`. В консоли вижу такое сообщение: ``` Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named _UITextLayoutView' ``` У меня в проекте есть экран с текстовым полем, созданным через Storyboard. Код выглядит примерно так: ```swift import UIKit class NoteViewController: UIViewController { @IBOutlet weak var textView: UITextView! override func viewDidLoad() { super.viewDidLoad() textView.text = "Заметка" textView.font = UIFont.systemFont(ofSize: 16) } } ``` Всё работало на Xcode 11.1, а после обновления — сразу краш. Пробовал чистить проект (Clean Build Folder), удалять Derived Data, переустанавливать Xcode — не помогает. Создал новый проект с нуля с UITextView — та же ошибка. Похоже, что проблема именно в Xcode 11.2. Кто-нибудь сталкивался? Как это исправить? Может быть, нужно что-то изменить в сториборде или добавить какой-то флаг? Буду благодарен за любую помощь! <<>>

Причина проблемы

Ошибка _UITextLayoutView возникает из-за того, что в Xcode 11.2 Apple изменила внутреннюю реализацию UITextView. В новой версии фреймворка появился приватный класс _UITextLayoutView, который используется для рендеринга текста. Однако старые storyboard или XIB-файлы, созданные в Xcode 11.1, не содержат информации об этом классе, что и вызывает краш при деархивации.

Проблема усугубляется тем, что Xcode 11.2 автоматически обновляет storyboard при открытии, но не всегда корректно добавляет новый класс. Если вы используете Interface Builder, он может сохранить ссылки на старую архитектуру.

Решение 1: Очистка и пересборка проекта (самый простой способ)

Сделайте полную очистку проекта и удалите все кэши:

  • Clean Build Folder: Product → Clean Build Folder (или Cmd+Shift+K)
  • Удалите Derived Data: Xcode → Preferences → Locations → нажмите на стрелку рядом с Derived Data и удалите папку
  • Удалите кэш Interface Builder: ~/Library/Caches/com.apple.dt.Xcode

После этого перезапустите Xcode и пересоберите проект. В большинстве случаев этого достаточно.

Решение 2: Изменение storyboard вручную (если первый способ не помог)

Откройте storyboard как исходный код (правой кнопкой мыши по файлу → Open As → Source Code). Найдите все вхождения UITextView и добавьте атрибут layoutManager:

<textView ...>
    <layoutManager>
        <layoutManager>
            <textContainer>
                <textContainer/>
            </textContainer>
        </layoutManager>
    </layoutManager>
</textView>

Это заставит Interface Builder правильно инициализировать UITextView с новым классом. После сохранения файла откройте его снова в Interface Builder и проверьте, что всё работает.

Решение 3: Программное создание UITextView (рекомендуется для долгосрочной стабильности)

Если вы хотите избежать подобных проблем в будущем, создавайте UITextView программно, а не через storyboard:

import UIKit

class NoteViewController: UIViewController {
    var textView: UITextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupTextView()
    }
    
    private func setupTextView() {
        textView = UITextView(frame: view.bounds)
        textView.text = "Заметка"
        textView.font = UIFont.systemFont(ofSize: 16)
        textView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(textView)
    }
}

Это полностью исключает зависимость от версии Xcode и даёт больше контроля над поведением.

Решение 4: Обновление Xcode до последней версии

Apple исправила эту проблему в Xcode 11.2.1 и новее. Обновитесь через Mac App Store или загрузите последнюю версию с Apple Developer Portal.

Важно: Если вы работаете в команде, убедитесь, что все разработчики используют одинаковую версию Xcode, иначе storyboard могут конфликтовать.

<<>>

Альтернативный подход: Использование XIB-файла вместо storyboard

Если вы не хотите переписывать весь код на программное создание, но storyboard продолжает падать, попробуйте вынести UITextView в отдельный XIB-файл. Это часто решает проблему, так как XIB-файлы менее подвержены багам при обновлении Xcode.

Создайте новый файл NoteView.xib, добавьте в него UITextView и подключите его через @IBOutlet. Затем загружайте вью из XIB:

class NoteViewController: UIViewController {
    @IBOutlet weak var textView: UITextView!
    
    override func loadView() {
        super.loadView()
        let nib = UINib(nibName: "NoteView", bundle: nil)
        let views = nib.instantiate(withOwner: self, options: nil)
        if let view = views.first as? UIView {
            self.view = view
        }
    }
}

Этот метод часто спасает, когда основной storyboard повреждён. Также рекомендуется удалить все UITextView из storyboard и добавить их заново в Interface Builder — иногда Xcode просто не обновляет старые объекты.

Если ничего не помогает, временно отключите UITextView в storyboard и замените его на UILabel с возможностью редактирования через код — это даст время дождаться исправления от Apple.