crash: UIAppearance, UIBarButtonItem, resizableImageWithCapInsets

Originator:michael.pederson
Number:rdar://11411000 Date Originated:5/8/2012
Status:Open Resolved:
Product:iPhone SDK Product Version:5.1
Classification:crash Reproducible:always
 
I've got a customization of UIBarButtonItem:
 
UIImage *buttonImage = [[UIImage imageNamed:@"button_nav_black"] resizableImageWithCapInsets:UIEdgeInsetsMake(14, 7, 14, 7)];
[[UIBarButtonItem appearance] setBackgroundImage:buttonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
buttonImage = [[UIImage imageNamed:@"button_nav_black"] resizableImageWithCapInsets:UIEdgeInsetsMake(12, 7, 12, 7)];
[[UIBarButtonItem appearance] setBackgroundImage:buttonImage forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];
A crash (seen at bottom) occurs when a view controller with custom left bar button item is popped off a navigation controller or when the iphone is rotated to landscape.  The crash does not occur if the UIAppearance customization is removed.  There's no problem if the view controller and bar button item are presented and dismissed modally.  There's no problem for a similarly customized back button item (different image, edge insets).  There's no problem if the view controller is pushed and popped in landscape.  So it seems the problem is with the UIBarMetricsDefault background image, except there's no crash if it's pushed in landscape, rotated to portrait, then popped.  The image itself is 20x29, so edge insets of 14 are appropriate for a one-pixel stretch in height.  Here things get really interesting, though Apple does state for -[UIImage resizableImageWithCapInsets:] "For best performance, use a tiled area that is a 1x1 pixel area in size."    If I change one of the top/bottom insets, the crash does not occur.  If I change both the top and bottom insets such that their average remains 14, the crash occurs.  If I change the left and right insets such that their sum remains 14, the crash occurs, with the exceptions of {14,4,14,10} and {14,14,14,0}.  The exceptions are slightly different for asymmetric top/bottom insets (that average to 14), for instance {12,8,16,6} does not crash.  But the invariant otherwise appears that the crash occurs when the sum of the left/right insets equals the average of the top/bottom insets when the top/bottom insets leave a single pixel uncapped.
 
As it happens, the edge insets are not really important for this image, and the image is stretched appropriately even when the customization is done without using a resizable image.
 
The crash looks like
-[_UIImageViewPretiledImageCacheKey hash]: message sent to deallocated instance 0x888add0
 
 
<_NSCallStackArray 0xe8d31f0>(
0   my_app                         0x00002600 start + 0,
1   CoreFoundation                      0x00d99cb2 _CF_forwarding_prep_0 + 50,
2   Foundation                          0x012a3cd1 objectHash + 33,
3   Foundation                          0x012a3af3 probeGC + 71,
4   Foundation                          0x012b8c48 -[NSConcreteMapTable removeObjectForKey:] + 57,
5   UIKit                               0x0201e625 -[_UIImageViewPretiledImageWrapper dealloc] + 81,
6   libobjc.A.dylib                     0x028f5e3d _objc_rootRelease + 47,
7   libobjc.A.dylib                     0x028f5e00 objc_release + 48,
8   libobjc.A.dylib                     0x028f6c50 _ZN12_GLOBAL__N_119AutoreleasePoolPage3popEPv + 528,
9   CoreFoundation                      0x00d67ea8 _CFAutoreleasePoolPop + 24,
10  CoreFoundation                      0x00d6a80b __CFRunLoopRun + 2011,
11  CoreFoundation                      0x00d69d84 CFRunLoopRunSpecific + 212,
12  CoreFoundation                      0x00d69c9b CFRunLoopRunInMode + 123,
13  GraphicsServices                    0x0445d7d8 GSEventRunModal + 190,
14  GraphicsServices                    0x0445d88a GSEventRun + 103,
15  UIKit                               0x01b96626 UIApplicationMain + 1163,
16  my_app                         0x000026bd main + 125,
17  my_app                         0x00002635 start + 53

Comments

Finally changing insets was working on debug development environment, but crash has been reproduced on other devices. Switched to stretchableImageWithLeftCapWidth:topCapHeight: instead.

Doh!

Just got the same stacktrace, using similar insets...

The extensive explanation is helping a lot, found a workaround thanks to you. {15, 7, 15, 7} crashed, {11, 7, 15, 7} works.

I guess that took some time to test and figure that. Thanks a lot for sharing... :)


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!