I have narrowed down an ugly bug, but since it seems like something internal to the nib/Interface Builder, I'm at a loss of what to do next.
I've got a UIView created in IB which functions as a custom dialog box. It shows a message and two buttons. (Proceed or Cancel.) Both buttons have a Background image set in Interface Builder.
Something is wrong with the way the background image for the cancel button is being handled. With NSZombieEnabled, I've been running the program. Most often, the method below logs this:
-[ModalDialog showInView:title:message:cancelText:proceedText:]
dialogProceedButton <UIButton: 0x7031f10; frame = (286 192; 90 31) // (etc.)
dialogProceedButtonBackground <UIImage: 0x3b36120>
dialogCancelButton <UIButton: 0x3b39cd0; frame = (104 192; 90 31) // (etc.)
dialogCancelButtonBackground <UIImage: 0x3b3a920>
That's completely normal. However, sometimes it does this (I can get this to repeat somewhat reliably if I "rush" the UI by rapid tapping some interface buttons):
-[ModalDialog showInView:title:message:cancelText:proceedText:]
dialogProceedButton <UIButton: 0x7031f10; frame = (286 192; 90 31) // (etc.)
dialogProceedButtonBackground <UIImage: 0x3b36120>
dialogCancelButton <UIButton: 0x3b39cd0; frame = (104 192; 90 31) // (etc.)
*** -[UIImage retain]: message sent to deallocated instance 0x3b3a920
As you can see, NSZombieEnabled found that the background image for the Cancel button has been deallocated, but is being sent a retain message. (Not by me, though... that image is only used for this one button, and only accessed in Interface Builder. I don't have any IBOutlets or any variables linked to that image.)
So, um, what now?
EDIT:
Sometimes, it's not a retain message that gets caught as a zombie, sometimes it's isKindOfClass:
//(the object address is always dialogCancelButton.currentBackgroundImage)
-[UIImage isKindOfClass:]: message sent to deallocated instance 0x1661f0
//occasionally, these come along, too:
*** NSInvocation: warning: object 0x7e0d0b0 of class '_NSZombie_UIImage' does not implement methodSignatureForSelector: -- trouble ahead
*** NSInvocation: warning: object 0x7e0d0b0 of class '_NSZombie_UIImage' does not implement doesNotRecognizeSelector: -- abort
This is my custom UIViews "showInView" method:
- (void)showInView:superView
title:(NSString*)title
message:(NSString*)message
cancelText:(NSString*)cancelText
proceedText:(NSString*)proceedText {
NSLog(@"%s",__PRETTY_FUNCTION__);
NSLog(@"dialogProceedButton %@", dialogProceedButton);
NSLog(@"dialogProceedButtonBackground %@", dialogProceedButton.currentBackgroundImage);
NSLog(@"dialogCancelButton %@", dialogCancelButton);
NSLog(@"dialogCancelButtonBackground %@", dialogCancelButton.currentBackgroundImage);
CGRect rect;
dialogTitle.text = title;
dialogMessage.text = message;
[dialogProceedButton setTitle:proceedText forState:UIControlStateNormal];
if (cancelText == @"") { // SINGLE BUTTON DIALOG
dialogCancelButton.hidden = YES;
rect = [dialogProceedButton frame];
rect.origin.x = 195; //center the button
[dialogProceedButton setFrame:rect];
} else {
[dialogCancelButton setTitle:cancelText forState:UIControlStateNormal];
dialogCancelButton.hidden = NO;
rect = [dialogProceedButton frame];
rect.origin.x = 286; //button on right of dialog box
[dialogProceedButton setFrame:rect];
}
[UIView beginAnimations:@"modalAppears" context:nil];
[UIView setAnimationDuration:0.5];
[superView addSubview:self];
self.alpha = 1.0;
[UIView commitAnimations];
}
Thanks!
Ok, this one's a what-the-heck. I decided to try reversing the images for the Proceed and Cancel buttons. The result was now that the Proceed button image would cause the crash (just as intermittently). I completely deleted the image from my project and from Interface Builder. I then added a fresh copy with a new name and hooked it up.
With the previous setup, I had been able to reproduce the crash about 40% of the time. I've tried about 20 times to reproduce the crash after these changes, and I cannot reproduce it at all now.
If the image or the nib was corrupted, why, why, why would it cause a random/intermittent symptom?
Whattathing. Hope it's well and truly fixed.
Update:
And... so there is a bit more to it. Turns out I discovered that I had coincidentally been using the same image as a placeholder in my (incomplete) instructions view. For temporary convenience there, I was using [UIImage imageNamed:] to grab the image. It was being properly allocated and released, but it seems that IB's cooperation with the imageNamed: method and/or cache is not perfect.
The fact that when I went and grabbed a fresh copy of the image, I also gave it a new name, meant that now the IB button image and the temporary placeholder image were no longer the same image at all.
I went back to a backup of my project from a couple days ago to test my theory. All I did was tell the instructions view to use a different placeholder image. Crashes stopped.
This is probably an SDK bug, then. There shouldn't be any reason not to use an image in IB and also use the same image elsewhere using imageNamed:. If I feel wily or bored one of these days, maybe I'll distill this down into an example project to send to Apple radar.
How is your XIB file wired to your view? What IBOutlets do you have defined? I really doubt you have solved your problem in the way you describe.
来源:https://stackoverflow.com/questions/1575529/uibutton-created-by-interface-builder-is-crashing