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

***由于未捕获异常'NSInvalidUnarchiveOperationException'而终止应用程序,原因:'无法实例化名为_UITextLayoutView的类,因为没有找到名为_UITextLayoutView的类;类需要在源代码中定义或从库中链接(确保类是正确目标的一部分)'

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


当前回答

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

这里是直接链接

其他回答

这是Xcode 11.2的一个bug。子类textview在所有没有安装新iOS版本(13.2)的设备上崩溃。您可能最好不要用那个版本构建一个发行版。

你现在可以:

把Xcode降级到11.1或者 把你的设备升级到iOS 13.2

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

此更新修复了一个可能导致使用UITextView的应用程序崩溃的关键问题

该问题已在Xcode 11.2.1中修复。

编辑:由于修复现在已经发布,你应该切换到Xcode版本并注释掉这个解决方案。Mojtaba Hosseini在他的答复中提到:

... 这最后两个灵活的变通方法使用了苹果私有API,将被苹果审查拒绝!

在苹果发布修复之前,这是一个继续开发和测试的好办法。


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

无需更改故事板文件!

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

//******************************************************************
// 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()
}

祝贺

Xcode的新版本(11.2.1)现在已经可用,这是摆脱这个问题的最好方法。

解决方法

@Mojtaba Hosseini我提出的解决方案是通过StackOverflow帮助和参与我的开发伙伴。你、我和所有其他开发者都知道,当苹果发布新版本时,这个问题就会消失。

除了一切

前面提到的解决方案肯定被Apple Review接受了,因为它完全不涉及私有API。这种方法非常类似于创建属性

@界面UITextView(布局)

Or

UITextView+Layout.h

因此,当你创建属性时,你直接使用APPLE私有组件,并根据你的需要重新模块化它们。

简单的例子是AMFNetworking类

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

希望我的指控已经结束了

下面的答案只是我的一些帮助,让开发者能够继续开发,因为我们最初建议开发者回滚Xcode。再次下载8gb的Xcode是一个糟糕的做法,因为我们都知道新版本的Xcode很快就会发布。

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

***由于未捕获异常'NSInvalidUnarchiveOperationException'而终止应用程序,原因:'无法实例化名为_UITextLayoutView的类,因为没有找到名为_UITextLayoutView的类;类需要在源代码中定义或从库中链接(确保类是正确目标的一部分)'

解决方案

进入构建设置搜索“DEAD_CODE_STRIPPING”并将其设置为NO

DEAD_CODE_STRIPPING = NO

Then

创建文件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

在app委托中执行它

#import "UITextViewWorkaround.h"

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

            [UITextViewWorkaround executeWorkaround];
    return yes;
    }

编译代码,你将有一个运行的应用程序:)

一个更快的解决方法:

///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。

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