从 Xcode 11.1 升级到 Xcode 11.2 后,应用程序因 _UITextLayoutView 而崩溃

After upgrading to Xcode 11.2 from Xcode 11.1, app crashes due to _UITextLayoutView

从 Xcode 11.1 升级到 Xcode 11.2 后,我的应用崩溃了:

*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named _UITextLayoutView because no class named _UITextLayoutView was found; the class needs to be defined in source code or linked in from a library (ensure the class is part of the correct target)'

为什么会这样?我怎样才能防止这次崩溃?

作为 "quick" 修复,您可以直接从代码而不是通过 IB 添加 UITextView。至少它对我有用。尽管从我的角度来看,最好回滚到以前的 Xcode/wait 来获得新的。

更新:已修复!

唯一的解决办法是更新

这个bug is fixed in Xcode 11.2.1. So you can download and use it from here.

Storyboards containing a UITextView will no longer cause the app to crash on operating system versions earlier than iOS 13.2, tvOS 13.2, or macOS 10.15.2. (56808566, 56873523)


Xcode Apple 于 2019 年 11 月 5 日弃用了 11.2

如果您尝试将使用 Xcode 11.2 构建的应用程序提交到 AppStore,您将被拒绝:

App Store 连接操作警告

WARNING ITMS-90703: "Deprecated Xcode Build. Due to resolved app archives issues, we have deprecated Xcode 11.2 on November 5, 2019. Download Xcode 11.2.1 or newer, rebuild your app and resubmit."

因此,使用 Xcode 11.2 完成的所有解决方法都是 无用的


这是 Xcode 11.2 的错误,已在 Xcode 11.2.1 中修复。

解决方案

回滚到以前的 Xcode release 版本来自: 回滚不再是一个选项,AppStore 将拒绝任何构建Xcode 低于 11.2.1 take a look at this

https://developer.apple.com/services-account/download?path=/Developer_Tools/Xcode_11.1/Xcode_11.1.xip

注意需要使用Safari下载,必须先login to Apple developer portal.

您可以在 https://developer.apple.com/download/more 此处找到所有其他 Xcode 版本和其他资源 link(包括发行版和测试版)

解决方法

这是非常困难但可行的解决方法。 将 storyboards 和 Xibs 中的所有 UITextViews 替换为 pure code 版本。


注意这个bug is found and fixed by Apple

还有更早的,the bug was confirmed by Apple Staff edford


对于 iOS 13.2 且不能再使用 Xcode 11.1 的用户:

  1. 将 macOS 更新到 10.15.1 或更高版本
  2. 安装 Xcode 11.2.1 或更高版本
  3. 现在应该可以在更新后的设备上使用了。

对于那些有故事板的人:

  1. 子类 UITextView
  2. 将其分配给所有 UITextView 个对象
  3. 不要忘记更新子类化中可能丢失的任何 属性 更改。

对于那些熟悉方法混合(对象和动态行为)的人

前往 @aftab muhammed khan and @MikRo

别再这样做了:

即使这最后两个 swizzling 解决方法没有使用 Apple private API,它们也会在 AppStore 中被拒绝,因为Apple will not accept builds with Xcode versions under 11.2.1

再一次:

Xcode Apple 于 2019 年 11 月 5 日弃用了 11.2

更新的解决方案: 更新至 Xcode 11.2.1。它适用于 iOS 11、12 或 13 台设备。

参考apple's documentation 此更新修复了一个可能导致使用 UITextView 的应用程序崩溃的严重问题。

旧解:https://developer.apple.com/download/more/ 下载 Xcode 11.1 从 11.2 切换回 11.1 修复了崩溃。

此外,对我来说,即使使用 Xcode 11.2,当我将 iPhone 升级到 13.2 时,也修复了崩溃问题。

更快的修复:

///Substitute class for _UITextLayoutView bug
class FixedTextView: UITextView {
    required init?(coder: NSCoder) {
        if #available(iOS 13.2, *) {
            super.init(coder: coder)
        }
        else {
            let rect = CGRect(origin: .zero, size: CGSize(width: 100, height: 44*3))
            super.init(frame: rect, textContainer: nil)
        }
    }
}

在某处添加此代码,然后将所有故事板实例替换为 FixedTextView

注意:您将丢失在故事板中创建的所有属性。这可能会产生严重影响(例如委托设置、大小等)

这是 Xcode 11.2 的错误。子类文本视图在所有未安装 neweset iOS build (13.2) 的设备上崩溃。您最好不要使用该版本构建版本。

您现在可以:

  • 将 Xcode 降级到 11.1 或
  • 将您的设备升级到 iOS13.2

改进@garafajon 的回答。对我来说,它在大多数情况下都有效。

///Substitute class for _UITextLayoutView bug
class FixedTextView: UITextView {
    required init?(coder: NSCoder) {
        if #available(iOS 13.2, *) {
            super.init(coder: coder)
        }
        else {
            super.init(frame: .zero, textContainer: nil)
            self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            self.contentMode = .scaleToFill

            self.isScrollEnabled = false   // causes expanding height

            // Auto Layout
            self.translatesAutoresizingMaskIntoConstraints = false
            self.font = UIFont(name: "HelveticaNeue", size: 18)
        }
    }
}

恭喜

Xcode 的新版本 (11.2.1) 现在可用,这是解决此问题的最佳方法。

解决方法

@Mojtaba Hosseini 我提出的解决方案来自我身边的开发人员通过 Whosebug 提供的帮助和参与。你、我和这里的所有其他开发人员都已经知道,当 Apple 发布新版本时,这个问题就会消失。

但除此之外

上述解决方案绝对被 Apple Review 接受,因为根本没有涉及私人 API。这种方法与创建 属性 like

非常相似

@interface UITextView (Layout)

UITextView+Layout.h

因此,当您创建 属性 时,您直接使用 APPLE 私有组件并根据您的依赖或要求重新调制它们。

简单示例是 AMFNetworking 类

- (void)setImageWithURL:(NSURL *)url {
    [self setImageWithURL:url placeholderImage:nil];
}

希望我已经完成了指控

下面的答案只是我这边的一些帮助,使开发人员能够继续开发,因为我们最初建议开发人员回滚 Xcode。再次下载 8 GB Xcode 是一种不好的做法,因为我们都知道 Xcode 的新版本即将发布。

虽然它已在 Xcode 11.2.1 中修复,但我为 Xcode 11.2 找到了一个解决方案,您可以通过它来摆脱此崩溃:

*** Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: 'Could not instantiate class named _UITextLayoutView because no class named _UITextLayoutView was found; the class needs to be defined in source code or linked in from a library (ensure the class is part of the correct target)'

解决方案

转到构建设置搜索 "DEAD_CODE_STRIPPING" 并将其设置为 NO

DEAD_CODE_STRIPPING = NO

然后

create files UITextViewWorkaround

UITextViewWorkaround.h

    #import <Foundation/Foundation.h>


    @interface UITextViewWorkaround : NSObject
    + (void)executeWorkaround; 
@end

UITextViewWorkaround.m

#import "UITextViewWorkaround.h"
#import  <objc/runtime.h>



    @implementation UITextViewWorkaround

    + (void)executeWorkaround {
        if (@available(iOS 13.2, *)) {
        }
        else {
            const char *className = "_UITextLayoutView";
            Class cls = objc_getClass(className);
            if (cls == nil) {
                cls = objc_allocateClassPair([UIView class], className, 0);
                objc_registerClassPair(cls);
    #if DEBUG
                printf("added %s dynamically\n", className);
    #endif
            }
        }
    }

    @end

execute it in the app delegate

#import "UITextViewWorkaround.h"

        - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
            // Override point for customization after application launch.

            [UITextViewWorkaround executeWorkaround];
    return yes;
    }

编译代码,您将拥有一个 运行 应用 :)

我已经将 khan 的 Obj-C 解决方案改编为 Swift:

import UIKit

@objc
class UITextViewWorkaround : NSObject {

    static func executeWorkaround() {
        if #available(iOS 13.2, *) {
        } else {
            let className = "_UITextLayoutView"
            let theClass = objc_getClass(className)
            if theClass == nil {
                let classPair: AnyClass? = objc_allocateClassPair(UIView.self, className, 0)
                objc_registerClassPair(classPair!)
            }
        }
    }

}

AppDelegatedidFinishLaunchingWithOptions末尾调用。

谢谢@Aftab!

此问题已在 Xcode 11.2.1 中修复。

编辑: 由于修复程序现已发布,您应该切换到那个 Xcode 版本并 注释掉 这个解决方法.正如 Mojtaba Hosseini 在他的回答中提到的:

... these last two swizzling workarounds are using Apple private API and will be reject from Apple review!

在 Apple 发布修复程序之前,这是一个很好的解决方法,可以继续开发和测试。


对于 Xcode 11.2,基于 Aftab Muhammed Khan 的想法并在 John Nimis 的帮助下,我刚刚测试了以下代码。

无需更改故事板文件!

编辑了我的 AppDelegate.swift 文件并添加了这个 class

//******************************************************************
// MARK: - Workaround for the Xcode 11.2 bug
//******************************************************************
class UITextViewWorkaround: NSObject {

    // --------------------------------------------------------------------
    // MARK: Singleton
    // --------------------------------------------------------------------
    // make it a singleton
    static let unique = UITextViewWorkaround()

    // --------------------------------------------------------------------
    // MARK: executeWorkaround()
    // --------------------------------------------------------------------
    func executeWorkaround() {

        if #available(iOS 13.2, *) {

            NSLog("UITextViewWorkaround.unique.executeWorkaround(): we are on iOS 13.2+ no need for a workaround")

        } else {

            // name of the missing class stub
            let className = "_UITextLayoutView"

            // try to get the class
            var cls = objc_getClass(className)

            // check if class is available
            if cls == nil {

                // it's not available, so create a replacement and register it
                cls = objc_allocateClassPair(UIView.self, className, 0)
                objc_registerClassPair(cls as! AnyClass)

                #if DEBUG
                NSLog("UITextViewWorkaround.unique.executeWorkaround(): added \(className) dynamically")
               #endif
           }
        }
    }
}

并在 "didFinishLaunchingWithOptions" 的委托调用中调用解决方法

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    // Override point for customization after application launch.

    // This is the workaround for Xcode 11.2
    UITextViewWorkaround.unique.executeWorkaround()
}

我使用了一个成功的解决方法,但是很痛苦。这是我遵循的过程:

  1. 在文本编辑器中打开 XIB
  2. 找出有问题的 TextView。就我而言:
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="782-j1-88c" customClass="LCAnsiConsoleTextView">
  <rect key="frame" x="16" y="20" width="343" height="589"/>
  <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
  <fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="12"/>
  <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
  1. 注意它的 id(在我的例子中:id="782-j1-88c"
  2. 覆盖上面答案中提到的 class 并重新创建选项(我的是 Objective-C,抱歉):
@implementation FixedTextView

- (id) initWithCoder:(NSCoder*)coder
{
    if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){13,2,0}])
        self = [super initWithCoder:coder];
    else {
        self = [super initWithFrame:CGRectMake(16, 3, 343, 605)];
        self.editable = YES;
        self.selectable = YES;
        self.insetsLayoutMarginsFromSafeArea = YES;
        self.clipsToBounds = YES;
        self.clearsContextBeforeDrawing = YES;
        self.autoresizesSubviews = YES;
        self.contentMode = UIViewContentModeScaleToFill;
        self.scrollEnabled = YES;
        self.userInteractionEnabled = YES;
        self.multipleTouchEnabled = YES;
        self.translatesAutoresizingMaskIntoConstraints = NO;
        self.font = [UIFont fontWithName:@"Menlo-Regular" size:12.0];
    }
    return self;
}
  1. 注意包含您的文本视图 ID 的约束,并针对您的视图或视图控制器中的其他元素 ID 重新创建这些约束。就我而言:
- (id) initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self xibSetup];
        [self initView];
/*
        <constraint firstItem="75C-lt-YtE" firstAttribute="top" secondItem="782-j1-88c" secondAttribute="bottom" constant="8" symbolic="YES" id="8SH-5l-FAs"/>
        <constraint firstItem="782-j1-88c" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leadingMargin" id="Mve-aZ-HCe"/>
        <constraint firstItem="782-j1-88c" firstAttribute="leading" secondItem="75C-lt-YtE" secondAttribute="leading" id="dPG-u3-cCi"/>
        <constraint firstItem="782-j1-88c" firstAttribute="trailing" secondItem="iN0-l3-epB" secondAttribute="trailingMargin" id="sjT-0Q-hNj"/>
        <constraint firstItem="782-j1-88c" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="vic-vZ-osR"/>
*/
        [self.command.topAnchor constraintEqualToAnchor:self.console.bottomAnchor constant:8].active = YES;
        [self.console.leadingAnchor constraintEqualToAnchor:self.layoutMarginsGuide.leadingAnchor].active = YES;
        [self.console.leadingAnchor constraintEqualToAnchor:self.command.leadingAnchor].active = YES;
        [self.console.trailingAnchor constraintEqualToAnchor:self.trailingAnchor].active = YES;
        [self.console.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor].active = YES;

    }
    return self;
}

这样做解决了我的问题,并且没有损失所需的功能。幸运的是我只有一个 UITextView 可以更换。否则,这就站不住脚了。

您可以从 Apple 开发者网站下载最新的 Xcode 测试版 (11.2.1 GM)。

Here the direct link

11.2.1 GM seed 解决了这个问题

(可用于发布到App Store)

前往 https://developer.apple.com/download/。下载Xcode 11.2.1 GM种子

Release notes 确认它修复了这个错误:

我遇到了同样的问题,我刚刚将 Xcode 11.2 升级到 11.2.1,它工作正常。

升级后,我在 iOs 13 和 iOS 12 上进行了相同的测试,并且工作正常。

此问题已在 Xcode 版本 11.2.1 中修复,并在发行说明中指出:

This update fixes a critical issue that could cause apps using UITextView to crash

1.问题:

Xcode 11.2 存在一个问题,其中如果使用 Xcode 编译,包含 UITextView 的故事板将导致应用程序在 iOS 13.2 之前的 OS 版本上崩溃11.2.

检查此 apple documentation

2。解决方案:

唯一的解决办法是将您的 Xcode 更新为 11.2.1 or 11.3.

Xcode 11.2.1 特别发布以解决此崩溃问题。

检查这个 apple documentation.

3。建议:

我建议您使用最新版本的 Xcode 11.3,因为它支持为 iOS 13.3 开发应用程序,而且还有许多新功能。 检查这个 apple documentation.