I am attempting to create a custom subclass of a UIView as follows:
I created a .xib with a UIView that contains a Picker object and Toolbar object, hooked up the Outlets and actions.
CustomPickerView.h
#import <UIKit/UIKit.h>
@interface CustomPickerView : UIView
@property (strong, nonatomic) IBOutlet UIDatePicker* datePicker;
@property (strong, nonatomic) IBOutlet UIBarButtonItem* doneButton;
-(IBAction) buttonDonePush:(id)sender;
@end
CustomPickerView.m
#import "CustomPickerView.h"
@implementation CustomPickerView
-(id) init
{
self=[[[NSBundle mainBundle] loadNibNamed:@"CustomPickerView" owner:self options:nil] objectAtIndex:0];
return self;
}
-(void) buttonDonePush:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:@"CustomPickerViewDoneButtonPush" object:nil userInfo:[NSDictionary dictionaryWithObject:self.datePicker.date forKey:@"date"]];
}
@end
And finally, in my ViewController I instantiate the object in the viewDidLoad method.
- (void)viewDidLoad
{
[super viewDidLoad];
self.customPickerView=[[CustomPickerView alloc] init];
self.customPickerView.datePicker.datePickerMode=UIDatePickerModeTime;
self.dateField.inputView=self.customPickerView;
}
When the user taps on the self.dateField, my CustomPickerView pops up nicely in place of the standard keyboard.
The problem is when the user taps the Done button from my CustomPickerView class, the buttonDonePush action does not fire.
This answer can be considered as the iOS companion to a similar solution I offered recently for iOSX:
Interface-Builder: "combine" NSView-class with .xib
Your arrangement is thus:
MyViewController.m
CustomPickerView.xib
You want to use your customPickerView as a subview of MyViewController.view and want to be able to access it's control widgets from the containing context.
In your example you are creating the customPickerView in code, but another useful scenario is to add it to the storyboard in Interface Builder. This solution will work for both scenarios.
In CustomViewPicker.h
declare IBOutlets for your interface elements. You have already done this for your datePicker and doneButton, but you also need an IBOutlet to a UIView which will be the containing view for these items.
In CustomViewPicker.xib
view
,datePicker
,doneButton
to their respective IB objectsbuttonDonePush
to thedoneButton
IB objectIn CustomViewPicker.m:
If you want to initialise in code (as you have done), your MyViewController would contain something like this:
[edit removed this redundant line:
[self.view addSubview:self.customPickerView];
]Alternatively you can create your CustomPickerView - and set it's frame - directly in the storyboard. Just add a custom view to your MyViewController's storyboard scene, and change it's class to CustomPickerView. Link it to your
self.customPickerView
IBOutlet.In this case
initWithFrame
does not get called, butawakeFromNib
is invoked when MyViewController loads it's CustomPickerView subview. Your MyViewController'sviewDidLoad
would then look like this:If you want to get your button push action out of the customPickerView, you might consider using a delegate, which could be more self-contained than your use of NSNotification (but that issue reaches beyond your original question).
EDIT:
An answer above pointed this out, but in the init method you are setting self, but this happens before self is ever initialized. If you could show the code where you are creating this specific view, it would help a lot. Here's my suggestion.
In your class that is controlling the deployment of this custom view:
In the CustomPickerView.m file, remove the init method.
PREVIOUS ANSWER:
You are using NSNotificationCenter in this implementation. When a user touches the done button, an
NSNotification
is posted. You must explicitly "opt in" and "listen" for these notifications. You do that by registering with the notification center.In viewDidLoad:
Then you need to implement the selector you specified up there: