I'm having a very weird problem, that I think I know why I'm getting it but I can't seem to think of a fix. I am convinced there is no compiler bug here. I have had many of those and all of them occurred because of my faulty code.
Basically, I have a view controller called UnlockKeyboardViewController that inherits from UIViewController, and a custom view (inheriting directly from UIView) called UnlockKeyboard. The header for UnlockKeyboard looks like this:
@interface UnlockKeyboard : UIView
{
NSArray *buttons;
NSArray *passcodeFields;
UIImage *buttonBackgroundImage;
UIImage *buttonBackgroundHighlightedImage;
UIImage *middleButtonBackgroundImage;
UIImage *middleButtonBackgroundImageHighlighted;
UIImage *screenBackgroundImage;
UIImage *infoViewContainerImage;
UIImage *keypadViewContainerImage;
UIImage *passcodeFieldsContainerImage;
UIImage *infoViewImage;
UIImage *passcodeViewImage;
UIView *infoViewContainer;
UIView *keypadViewContainer;
UIView *passcodeFieldsContainer;
UIView *infoView;
UIView *keypadView;
UIView *passcodeFieldsView;
UIView *infoToDisplayView; //The view the programmer passes to show in infoView.
}
@property(nonatomic, retain)UIImage *buttonBackgroundImage;
@property(nonatomic, retain)UIImage *buttonBackgroundHighlightedImage;
@property(nonatomic, retain)UIImage *screenBackgroundImage;
@property(nonatomic, retain)UIImage *keypadViewBackgroundImage;
@property(nonatomic, retain)UIImage *infoViewContainerImage;
@property(nonatomic, retain)UIImage *keypadViewContainerImage;
@property(nonatomic, retain)UIImage *passcodeFieldsContainerImage;
@property(nonatomic, retain)UIImage *infoViewImage;
@property(nonatomic, retain)UIImage *passcodeViewImage;
@property(nonatomic, retain)UIView *infoToDisplayView;
//Properties for container views.
@property(nonatomic, retain)UIView *infoViewContainer;
@property(nonatomic, retain)UIView *keypadViewContainer;
@property(nonatomic, retain)UIView *passcodeFieldsContainer;
@end
The UnlockKeyboardViewController implementation looks like this so far:
@implementation UnlockKeyboardViewController
-(id)init
{
if((self = [super init]))
{
self.view = [[UnlockKeyboard alloc] init];
}
return self;
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[UIView animateWithDuration:0.7 animations:^{
self.view.keypadViewContainer.frame = CGRectMake(0, 261, 320, 200);
} completion:^(BOOL finished){
}];
}
-(void)dealloc
{
[super dealloc];
}
@end
This is were my problem gets interesting. Whenever I try to compile, the Terminal (this is a jailbreak app, so no Xcode) gives me the following error:
In function ‘void __-[UnlockKeyboardViewController viewDidAppear:]_block_invoke_1(void*)’:
Segmentation fault: 11
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://developer.apple.com/bugreporter> for instructions.
BUT, this error only appears when I have this line in:
self.view.keypadViewContainer.frame = CGRectMake(0, 261, 320, 200);
If I don't that line in my animation block, the compiler won't give me that error and it wil compile just fine. Although, no matter were I put this line, I always get segmentation line 11.
I THINK this may have something to do with the fact that UIView doesn't have a member called keypadViewContainer, although UnlockKeyboard has that property and is a subclass of UIView. I believe this is happening because the compiler can't actually see the class hierarchy between UIView and UnlockKeyboard.
If I'm right, I have no idea of how to go around the problem. Been thinking for a while. Any input to help me solve this problem will be really appreciated.
First, you should only set a view controller's view property in its loadView
method:
- (void)loadView
{
self.view = [[UnlockKeyboard alloc] init];
}
This will trigger other methods, such as viewDidLoad
, that will expect the object to have been full initialized. Moral of the story: don't set the view
property until the controller asks you to.
Then, in your viewDidAppear:
method, casing the view
property into the specific subclass you are using should avoid any warnings and hopefully also that weird compiler crash:
[UIView animateWithDuration:0.7 animations:^{
UnlockKeyboard *ukView = (UnlockKeyboard *)self.view;
ukView.keypadViewContainer.frame = CGRectMake(0, 261, 320, 200);
The code as you have written it should have triggered a compiler warning, because the property keypadViewContainer
isn't defined on UIView
(the type of the expression self.view
).
The type cast is admittedly a little bit ugly, but it's necessary since the view controller is a generic parent class and doesn't know what kind of view it is controlling. You may find it useful to define a property that eliminates the need to do the cast all the time:
@property (nonatomic,readonly) UnlockKeyboard *unlockKeyboardView;
And the corresponding method:
- (UnlockKeyboard *)unlockKeyboardView
{
return self.view;
}