UITableViewController subclass designated initializer calls [super initWithStyle:] and asserts on all UITableViewController designated initializers. Crash
Originator: | henriqueponde90 | ||
Number: | rdar://23709930 | Date Originated: | 12/1/2015 |
Status: | Closed | Resolved: | No |
Product: | iOS | Product Version: | 8.4 |
Classification: | Crash | Reproducible: | Always |
Link to Project:https://www.dropbox.com/s/rd24tv30wfv9con/TestTableViewControllerDesignatedInitializers.zip?dl=0 Link to Crash: https://www.dropbox.com/s/fk9tvjt388afa3m/TestTableViewControllerDesignatedInitializers.crash?dl=0 Summary: I have a subclass of UITableViewController, let's call it TestTableViewController and I only want one designated initializer for it, let's say initWithTitle: The implementation of initWithTitle: calls [super initWithStyle:] following the guidelines on how designated initializers should call a super designated initializer. Since I don't want other initializers to be called, I decided to make the 3 designated initializers of the super class unavailable. These are namely: - (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER; - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_DESIGNATED_INITIALIZER; - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER; So in TestTableViewController.h I add the NS_UNAVAILABLE to them and in TestTableViewController.m I make them crash like so: - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE; // FIXME:(hponde) - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE; - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE; and - (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE { [self doesNotRecognizeSelector:_cmd]; return nil; } - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil NS_UNAVAILABLE { [self doesNotRecognizeSelector:_cmd]; return nil; } - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_UNAVAILABLE { [self doesNotRecognizeSelector:_cmd]; return nil; } This causes a crash because of the following chain of calls: [TestTableViewController initWithTitle:] [UITableViewController initWithStyle:] [TestTableViewController initWithNibName:bundle:] So it seems that [UITableViewController initWithStyle:], a designated initializer, is calling [self initWithNibName:bundle:], another designated initializer. This is a violation of the initialization contract, since designated initializer cannot call another initializer in the same class. Steps to Reproduce: 1. Build the project attached and run 2. Crash Expected Results: Should not crash, I'm following the initialization contracts but UITableViewController is not. And that behavior is opaque to me. Actual Results: Crash with the stack: 2015-12-01 11:34:55.439 TestTableViewControllerDesignatedInitializers[2820:20725394] [31m-[TestTableViewController initWithNibName:bundle:]: unrecognized selector sent to instance 0x7f9c1153e4e0 [0m2015-12-01 11:34:55.441 TestTableViewControllerDesignatedInitializers[2820:20725394] [31m*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestTableViewController initWithNibName:bundle:]: unrecognized selector sent to instance 0x7f9c1153e4e0' *** First throw call stack: ( 0 CoreFoundation 0x000000010d6aec65 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x000000010d347bb7 objc_exception_throw + 45 2 CoreFoundation 0x000000010d6b60ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205 3 TestTableViewControllerDesignatedInitializers 0x000000010ce0e84d -[TestTableViewController initWithNibName:bundle:] + 93 4 UIKit 0x000000010dd9b831 -[UITableViewController initWithStyle:] + 45 5 TestTableViewControllerDesignatedInitializers 0x000000010ce0e966 -[TestTableViewController initWithSingleItem:] + 86 6 TestTableViewControllerDesignatedInitializers 0x000000010ce0e3d3 -[ViewController viewDidLoad] + 115 7 UIKit 0x000000010dbd81d0 -[UIViewController loadViewIfRequired] + 738 8 UIKit 0x000000010dbd83ce -[UIViewController view] + 27 9 UIKit 0x000000010daf3289 -[UIWindow addRootViewControllerViewIfPossible] + 58 10 UIKit 0x000000010daf364f -[UIWindow _setHidden:forced:] + 247 11 UIKit 0x000000010daffde1 -[UIWindow makeKeyAndVisible] + 42 12 UIKit 0x000000010daa3417 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2732 13 UIKit 0x000000010daa619e -[UIApplication _runWithMainScene:transitionContext:completion:] + 1349 14 UIKit 0x000000010daa5095 -[UIApplication workspaceDidEndTransaction:] + 179 15 FrontBoardServices 0x00000001102685e5 __31-[FBSSerialQueue performAsync:]_block_invoke_2 + 21 16 CoreFoundation 0x000000010d5e241c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12 17 CoreFoundation 0x000000010d5d8165 __CFRunLoopDoBlocks + 341 18 CoreFoundation 0x000000010d5d7f25 __CFRunLoopRun + 2389 19 CoreFoundation 0x000000010d5d7366 CFRunLoopRunSpecific + 470 20 UIKit 0x000000010daa4b02 -[UIApplication _run] + 413 21 UIKit 0x000000010daa78c0 UIApplicationMain + 1282 22 TestTableViewControllerDesignatedInitializers 0x000000010ce0e75f main + 111 23 libdyld.dylib 0x000000010fc52145 start + 1 24 ??? 0x0000000000000001 0x0 + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException [0m Version: iOS 8.4 Notes: Does not happen on iOS 9. Since I need to keep iOS 8 support, I can't have the checks Configuration: Simulator iPhone 6 Attachments: 'TestTableViewControllerDesignatedInitializers.crash' and 'TestTableViewControllerDesignatedInitializers.zip' were successfully uploaded.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!