After upgrading to Xcode 11.2 from Xcode 11.1, app crashes due to _UITextLayoutView
Update: Fixed!
The ONLY Solution is to update
This 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 11.2 is deprecated by Apple on November 5, 2019
if you ever try to submit your app that build with Xcode 11.2 to the AppStore, you will be rejected:
App Store Connect Operation Warning
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."
So all workarounds done with the Xcode 11.2 is useless
It's a bug for Xcode 11.2, and fixed in Xcode 11.2.1.
Solution(s)
Roll back to previous Xcode release version from: Rollback is not an option anymore and AppStore will reject any build with Xcode below 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
Note that you should use Safari to download it and you must first login to Apple developer portal.
You can find all other Xcode versions and other resources link (including release and beta versions) here at https://developer.apple.com/download/more
The workaround
This is very hard but working workaround.
Replace all UITextView
s in storyboards and Xibs with the pure code version.
Note that this bug is found and fixed by Apple
Also earlier, the bug was confirmed by Apple Staff edford
For those with iOS 13.2 and can not use Xcode 11.1 anymore:
- Update macOS to 10.15.1 or later
- Install Xcode 11.2.1 or later
- It should be work now on the updated device.
For those with storyboard:
- Subclass
UITextView
- Assign it to all
UITextView
objects - Don't forget to update any property changes that may lose in the subclassing.
For those comfortable with method swizzling (Objc and dynamic behavior)
Head to the @aftab muhammed khan answer for Objective-C and @MikRo answer for Swift adapted version
Just don't do it anymore:
Even if these last two swizzling workarounds are not using Apple private API, they will be rejected in AppStore because Apple will not accept builds with Xcode versions under 11.2.1!
And once again:
Xcode 11.2 is deprecated by Apple on November 5, 2019
Congratulation
The New version of Xcode (11.2.1) is available now which is the best way to get rid off this issue.
Workarounds
@Mojtaba Hosseini the solution I proposed was from the help and the participation from my side to my fellow developers over StackOverflow. You, me and all the rest of the developer here already know that when the new version is announced by Apple, this issue will be gone.
But Beside Everything
The solution aforementioned was definitely accepted by Apple Review as there is no private API involved at all. This approach is very similar to the creating property like
@interface UITextView (Layout)
Or
UITextView+Layout.h
So when you are creating property you are directly using APPLE Private Components and re-moduling them as per you depends or requirement.
The Simple Example is AMFNetworking classes
- (void)setImageWithURL:(NSURL *)url {
[self setImageWithURL:url placeholderImage:nil];
}
Hope I am done with the Allegation
The answer below was just some help from my side to enable developer to continue developing as you we initially proposed developer to roll back Xcode. This was a bad practice to download 8 GB Xcode again since we all know that the new version of Xcode will be released soon.
While it is fixed in Xcode 11.2.1, I got one solution for Xcode 11.2 by which you can get rid off this crash:
*** 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)'
SOLUTION
Go to the Build Setting search for "DEAD_CODE_STRIPPING" and set it to NO
DEAD_CODE_STRIPPING = NO
Then
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;
}
Compile the code and you will have a running app :)
The issue was fixed in Xcode 11.2.1.
EDIT: As the fix is now released, you should switch to that Xcode version and comment out this workaround. As Mojtaba Hosseini in his answer mentioned:
... these last two swizzling workarounds are using Apple private API and will be reject from Apple review!
For the time until the fix was released by Apple, this was a good workaround to continue developing and testing.
For Xcode 11.2, based on the idea of Aftab Muhammed Khan and with the help of John Nimis I just tested the following code.
No change in the storyboard files necessary!
Edited my AppDelegate.swift file and added this 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
}
}
}
}
and within the delegate call for "didFinishLaunchingWithOptions" call the workaround
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()
}