Xcode 13 beta 5错误: UIViewController在初始化期间缺少其初始特征集合

4

在 Xcode 13 beta 5 构建之前,应用程序运行良好。

我们的视图控制器中在此初始化代码行突然出现了以下错误:

init(dataProvider: DataProvider) {
    self.dataProvider = dataProvider
    super.init(style: .plain)
    dataProvider.delegate = self
}

这段代码在Xcode 12中运行良好,但现在没有任何更改就出现了以下错误:

'NSInternalInconsistencyException', reason: 'UIViewController缺少在初始化期间填充其初始特征集合。这是一个严重的错误,可能是由于在调用UIViewController初始化程序之前访问视图控制器上的属性或方法引起的。 视图控制器:'

我在谷歌上搜寻,只找到了1个关于该问题的晦涩主题帖,但对我来说没有什么帮助。

有时候设置断点并逐步执行可以避免崩溃,因此似乎存在某种布局竞态条件,但我无法调试。我尝试放置一个休眠函数,但那也不管用。

如有任何有关如何调试此问题的建议均可接受。目前我无法获得额外的信息用于调试。 如果您知道可能导致此问题的原因或应该去哪里查找,请告诉我。

以下是错误堆栈跟踪:

*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff203fc8a8 __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff2019ebe7 objc_exception_throw + 48
    2   Foundation                          0x00007fff207501c9 -[NSMutableDictionary(NSMutableDictionary) classForCoder] + 0
    3   UIKitCore                           0x00007fff248310ed UIViewControllerMissingInitialTraitCollection + 188
    4   UIKitCore                           0x00007fff24835616 -[UIViewController traitCollection] + 155
    5   UIKitCore                           0x00007fff24824392 -[UITableViewController dealloc] + 196
    6   App Dev                             0x000000010e4f5680 $s05AppLaB027MyViewController
    C14paymentMethods13selectedIndex5offer8delegateACSaySo16AppPaymentMethodCG_SiAA5Offer_pAA08CheckoutcD8Delegate_pSgtcfc + 368
    7   App Dev                             0x000000010e4f5726 $s05AppLaB027MyViewController
    C14paymentMethods13selectedIndex5offer8delegateACSaySo16AppPaymentMethodCG_SiAA5Offer_pAA08CheckoutcD8Delegate_pSgtcfcTo + 102
    8   App Dev                             0x000000010e289291 -[CartViewController showPaymentMethodPickerWithPaymentMethods:] + 385
    9   App Dev                             0x000000010e289055 __59-[CartViewController showPaymentMethodPickerOrEntryForm]_block_invoke + 245
    10  App Dev                             0x000000010e7075ae $sSo16AppServiceResultVSo7NSArrayCSgSo7NSErrorCSgIeyByyy_ABSaySo16AppPaymentMethodCGSgs5Error_pSgIegygg_TR + 222
    11  App Dev                             0x000000010e707246 $sSo17AppAccountServiceC05AppLaD0E19fetchPaymentMethods11forListType7refresh09preferredF6Method10completionSo17AppRequestReceipt_pSgAC0fmiJ0O_S2bySo16AppServiceResultV_SaySo010AppPaymentM0CGSgs5Error_pSgtcSgtFyAN_ArTtcfU_ + 630
    12  App Dev                             0x000000010e707333 $sSo17AppAccountServiceC05AppLaD0E19fetchPaymentMethods11forListType7refresh09preferredF6Method10completionSo17AppRequestReceipt_pSgAC0fmiJ0O_S2bySo16AppServiceResultV_SaySo010AppPaymentM0CGSgs5Error_pSgtcSgtFyAN_ArTtcfU_TA + 35
    13  App Dev                             0x000000010e580474 $sSo16AppServiceResultVSaySo16AppPaymentMethodCGSgs5Error_pSgIegygg_ABSo7NSArrayCSgSo7NSErrorCSgIeyByyy_TR + 212
    14  App Dev                             0x000000010e39bcad __79-[AppAccountV3DAO fetchPaymentMethodsRefresh:preferredPaymentMethod:withBlock:]_block_invoke + 45
    15  libdispatch.dylib                   0x0000000110c18a18 _dispatch_call_block_and_release + 12
    16  libdispatch.dylib                   0x0000000110c19bfc _dispatch_client_callout + 8
    17  libdispatch.dylib                   0x0000000110c28366 _dispatch_main_queue_callback_4CF + 1195
    18  CoreFoundation                      0x00007fff2036a555 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    19  CoreFoundation                      0x00007fff20364db2 __CFRunLoopRun + 2772
    20  CoreFoundation                      0x00007fff20363dfb CFRunLoopRunSpecific + 567
    21  GraphicsServices                    0x00007fff2cbb5cd3 GSEventRunModal + 139
    22  UIKitCore                           0x00007fff24fee193 -[UIApplication _run] + 928
    23  UIKitCore                           0x00007fff24ff2bfb UIApplicationMain + 101
    24  App Dev                             0x000000010e267120 main + 96
    25  dyld                                0x0000000110654e1e start_sim + 10
    26  ???                                 0x0000000000000001 0x0 + 1
    27  ???                                 0x0000000000000001 0x0 + 1
)
2个回答

2

在注释掉很多代码后,我开始遇到一个新的错误:

致命错误:使用未实现的初始化程序‘init(style :)’来调用类‘PaymentPickerViewController’

进一步研究行为后,似乎我们有一个objc初始化的扩展。我认为在这个Xcode 13中,objc代码被搞乱了,并且没有“看到”初始化程序的根调用。

我们最初的init代码路径是这样的:

@objc extension PaymentPickerViewController {
    convenience init() {
        dataProvider = DataProvider()
        self.init(dataProvider: dataProvider)
    }
}

init(dataProvider: DataProvider) {
   self.dataProvider = dataProvider
   super.init(style: .plain)        
}

修复方法是明确地覆盖了我们想要使用的超类swift init函数。
override init(style: UITableView.Style) {
    super.init(style: .plain)
     self.dataProvider = DataProvider()
}

这会强制objc查看正确的init,然后它就能正常工作了。

我担心我最初发布的错误非常误导人,所以希望这可以帮助任何遇到此问题的人。


我必须尊重地表示不同意。最初的错误是由于Objective C无法看到初始化程序而导致的,这只在xcode 13中开始发生。如果您检查谷歌,几乎没有关于此错误的信息。该错误本身具有误导性,真正的源似乎是objc代码无法看到swift初始化程序。如果有更多的清晰度,您可以提出建议,但我相信这个答案是解决方法。 - Aggressor
我在评估那个参数时遇到了一些麻烦,因为你的代码无法编译。那是你真正的代码吗?例如,你说 self.init(dp:),但你没有 init(dp:);你有一个不同的初始化程序,init(dataProvider:)。我不明白所有这些是如何联系在一起的;似乎缺少了一些拼图的部分。 - matt
我更新了init。这是代码的模拟表示。问题的根源在于:在Swift类中,作为objc扩展的init方法在运行时未被objc代码看到。通过显式地覆盖我们需要使用的tableview init,解决了这个问题。 - Aggressor
这个答案更多地讨论了编译器为什么看不到init:https://dev59.com/questions/YV4c5IYBdhLWcg3wM3-R#28187653。为什么在Xcode 13中突然出现这种情况,以及为什么它会作为我最初发布的错误传播,只有苹果公司能告诉你。 - Aggressor
1
在我深入探讨之前,这里的回答是否相关?https://dev59.com/GV8e5IYBdhLWcg3w_-r0#30719434 - matt
1
我不这么认为,不。 - Aggressor

0

简短描述:针对基于Objective-C的实现,可以将对象方法转换为类方法。

以下错误在xcode13 GM Seed上报告。错误日志:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'UIViewController is missing 
its initial trait collection populated during initialization. This is 
a serious bug, likely caused by accessing properties or methods on the 
view controller before calling a UIViewController initializer. View 
controller: <MyViewController: 0x7fa5ae2356c0>'

对于以下的init方法

- (instancetype)initWithModel:(MyModel *)myModel {
    
    MyViewController *vc = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"MyViewController"];
    vc.model = myModel;
    return vc;
}

init 是从另一个 View Controller 中以以下方式调用的。

// Before - invoking object method -- Results in the error
MyViewController *viewController = [[MyViewController alloc] initWithModel:testModel];

// After - invoking Class method
MyViewController *viewController = [MyViewController initWithModel:testModel];

为了解决这个问题,我将init方法转换为类方法。
+ (instancetype)initWithModel:(MyModel *)myModel {
    
    MyViewController *vc = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"MyViewController"];
    vc.model = myModel;
    return vc;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接