Linking against iOS 6 breaks iOS 5 UISearchBar/UIResponder

Originator:jack
Number:rdar://12460744 Date Originated:09-Oct-2012 10:26 AM
Status:Open Resolved:
Product:iPhone SDK Product Version:iOS 6.0
Classification:Crash/Hang/Data Loss Reproducible:Always
 
Summary:

Classes that inherit from UIResponder get a readonly property called inputAccessoryView of type UIView. The documentation's discussion paragraph talks about how consumers of UIKit classes that inherit from UIResponder can mutate this property: 
---
The default value of this property is nil. Subclasses that want to attach custom controls to either a system-supplied input view (such as the keyboard) or a custom input view (one you provide in the inputView property) should redeclare this property as readwrite and use it to manage their custom accessory view. When the receiver subsequently becomes the first responder, the responder infrastructure attaches the view to the appropriate input view before displaying it.
---

UISearchBar inherits from UIResponder, therefore on iOS 5.x it was acceptable to subclass UISearchBar and redeclare UIResponder's inputAccessoryView as readwrite and then set it to any object inheriting from or of type UIView.

Under iOS 6, Apple have already re-declared UISearchBar's inputAccessoryView as readwrite. Therefore when linking against iOS 6 the compiler ignores my property redeclaration because it is the same as the declaration that now exists on UISearchBar.

Steps to Reproduce:

1. Create a view-based iOS app (non-storyboard). Set the base SDK as 5.0 and link against the 6.0 SDK.
2. Create a subclass of UISearchBar and redeclare the inputAccessoryView property as @property (nonatomic, readwrite, strong).
3. In the view controller's nib, add a UISearchBar and change the UISearchBar object's class to your subclass. Hook up an outlet on your view controller to the UISearchBar object.
4. In the view controller's implementation file, create a UIView with a red background and set it as the UISearchBar subclass's inputAccessoryView using -[MySearchBarSubclass setInputAccessoryView:].
5. Compile and run on the iOS 6 simulator.
6. Compile and run on the iOS 5.0 or 5.1 simulator.

Expected Results:

Running on the iOS 6 simulator AND iOS 5 simulator does not crash the app and when you tap on the search bar it displays the keyboard attached to a red UIView.

Actual Results:

iOS 6 simulator: Behavior is as expected.
iOS 5 simulator: Crash on load: -[MySearchBarSubclass setInputAccessoryView:]: unrecognized selector sent to instance.

Regression:

To get around this you can conditionally (ios 5 vs ios 6) iterate through the subviews of the UISearchBar and find a view of class UITextField and attach the subview to it, however this is extremely brittle.

Notes:

I tried redeclaration at runtime:
objc_property_attribute_t type = { "T", "@\"UIView\"" };
objc_property_attribute_t ownership = { "N", "" };
objc_property_attribute_t backingivar  = { "V", "_inputAccessoryView" };
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty([UISearchBar class], "inputAccessoryView", attrs, 3);

But it ignored my backing ivar part and when I printed the property attributes of the property I created via property_getAttributes() it gave me back "T@\"UIView\",&,N which doesn't match the signature it should have, which is "T@\"UIView\",&,N,V_inputAccessoryView".

This is most likely because the compiler is what's generating the accessor/mutator pair and I don't have access to the ivar so I can't implement my own.

Regardless, using the runtime to do this is even more brittle than iterating through the UISearchBar's subviews.

Also I'm not sure I understand why Apple decided to redeclare it for me. Sure, it's somewhat convenient, but it breaks a lot of code for a lot of people and it goes against what UIResponder promises of UIKit classes that inherit from it.

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!