12
votes

I have a cryptic EXC_BAD_ACCESS when changing some UILabel's frame. The crash is random, usually I have to repeat the conditions for several minutes.

Enabling NSZombies, as well as other memory debug flags (NSDebugEnabled, MallocStackLogging), doesn't help, the crash stills stays as opaque : just a BAD_ACCESS with no message in the console. The target seems correct and alive, so it doesn't look like a deallocated memory problem.

To get some more info, I subclassed UILabel and rewrote the crashing function :

@implementation TestUILabel
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
    return [super actionForLayer:layer forKey:event];
}
@end

It crashes in the super's method, but on inspection everything seems correct (printing retainCount for 'self' and 'layer' gives respectively 3 and 2) :

(gdb) po self

< TestUILabel: 0x6ac2800; baseClass = UILabel; frame = (173 174; 0 0); text = '54 m²'; opaque = NO; autoresize = LM+TM; autoresizesSubviews = NO; userInteractionEnabled = NO; animations = { position=< CABasicAnimation: 0xe07ba60>; }; layer = < CALayer: 0xbf1b950>>

(gdb) po event

bounds

(gdb) po layer

< CALayer:0xbf1b950; position = CGPoint (173 174); bounds = CGRect (0 0; 0 0); delegate = < TestUILabel: 0x6ac2800; baseClass = UILabel; frame = (173 174; 0 0); text = '54 m²'; opaque = NO; autoresize = LM+TM; autoresizesSubviews = NO; userInteractionEnabled = NO; animations = { position=< CABasicAnimation: 0xe07ba60>; }; layer = < CALayer: 0xbf1b950>>; contents = < CGImage 0xe04ed60>; opacity = 1; animations = [position=< CABasicAnimation: 0xe07ba60>]>

Did someone get a similar problem ? Or have any ideas where this could come from ?

Thanks in advance !

Edit: here's the complete crash backtrace :

Thread 1, Queue :
com.apple.main-thread
#0 0x00459b2c in -[UIView(CALayerDelegate) actionForLayer:forKey:] ()
#1 0x00eaaac7 in -[CALayer actionForKey:] ()
#2 0x00ea80fe in actionForKey(CALayer*, CA::Transaction*, NSString*) ()
#3 0x00ea8066 in beginChange(CALayer*, CA::Transaction*, unsigned int, objc_object*&) ()
#4 0x00eaba3a in CALayerSetPosition(CALayer*, CA::Vec2 const&, bool) ()
#5 0x00eab8b5 in -[CALayer setPosition:] ()
#6 0x00eab7cc in -[CALayer setFrame:] ()
#7 0x0045739d in -[UIView(Geometry) setFrame:] ()
#8 0x00542a68 in -[UILabel setFrame:] ()
#9 0x0000a97f in -[MosaicElementView setupWithAdvert:] at /Users/eino/Prog/AJ/Classes/Search/SubViews/MosaicElementView.m:30
#10 0x00079cb9 in -[SearchResultsViewController setupElement:withCell:indexPath:actualIndex:] ()
#11 0x000797a2 in -[SearchResultsViewController tableView:cellForRowAtIndexPath:] ()
#12 0x004957fa in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:withIndexPath:] ()
#13 0x0048b77f in -[UITableView(UITableViewInternal) _createPreparedCellForGlobalRow:] ()
#14 0x004a0450 in -[UITableView(_UITableViewPrivate) _updateVisibleCellsNow:] ()
#15 0x00498538 in -[UITableView layoutSubviews] ()
#16 0x00eb0451 in -[CALayer layoutSublayers] ()
#17 0x00eb017c in CALayerLayoutIfNeeded ()
#18 0x00ea937c in CA::Context::commit_transaction(CA::Transaction*) ()
#19 0x00ea90d0 in CA::Transaction::commit() ()
#20 0x00ed97d5 in CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) ()
#21 0x017e9fbb in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#22 0x0177f0e7 in __CFRunLoopDoObservers ()
#23 0x01747bd7 in __CFRunLoopRun ()
#24 0x01747240 in CFRunLoopRunSpecific ()
#25 0x01747161 in CFRunLoopRunInMode ()
#26 0x01e7d268 in GSEventRunModal ()
#27 0x01e7d32d in GSEventRun ()
#28 0x0043042e in UIApplicationMain ()
#29 0x000021fe in main at /Users/eino/Prog/AJ/main.m:11

The crasing line from frame 9 is basically just the frame change :

labelPrice.frame = rect;

with rect being a correct CGRect (106, 143, 86, 22).

2
Can you add the values for event? Could it be a bad key?Mr. Berna
here i posted the crash log :)Eino Gourdin
Mr Berna, no unfortunately, event is just a string containing @"bounds"Eino Gourdin
Can you show the declaration of the rect variable? Don't you mean CGRectMake(106, 143, 86, 22); instead of CGRect(106, 143, 86, 22);? Also can you show the instantiation of your UILabel? Have you tried using the initWithFrame: constructor instead of setting the frame property?fulvio
labelPrice is an IBOutlet to an object instantiated from a xib file. However its size has to change to accomodate new text, so this line has to be called. Even then, it works fine 99,5% of the time, as it should. As for the rect variable, it is indeed directly a CGRectMake in production code, however after tests I have already discarded the possibility of the problem being there : when the crash occurs, the used CGRect has always correct values (like 106, 143, 86, 22) ; so the failure comes from the setFrame: itself, not from the CGRect construction, that's why I left this part out.Eino Gourdin

2 Answers

10
votes

You probably already checked for this, but it's worth shot...

Are you certain that you aren't doing anything that would effect any UI elements in a background thread? Perhaps you're doing some computation related to this search and it changes a property of some view.

I have seen his sort of thing in cases where I forgot a performSelectorOnMainThread:withObject:waitUntilDone: call and then altered the UI in the background.

1
votes

This crash has non-main threads that appear to use UIKit classes or functions. Generally speaking, it is only safe to use UIKit from the main thread. Calling into UIKit from background threads can cause unpredictable behavior (like crashes!). Please double check that all of your code (that is not on the main thread) has been explicitly marked as safe to use in the background by Apple.

External resources:

UIKit Framework Reference