简体   繁体   English

Objective-C自定义类动作和输出

[英]Objective-C Custom Class Actions and Outlets

I am attempting to create a custom subclass of a UIView as follows: 我试图创建一个UIView的自定义子类,如下所示:

I created a .xib with a UIView that contains a Picker object and Toolbar object, hooked up the Outlets and actions. 我使用UIView创建了一个.xib,其中包含一个Picker对象和Toolbar对象,并连接Outlets和操作。

在此处输入图片说明

CustomPickerView.h 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 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. 最后,在ViewController中,我在viewDidLoad方法中实例化该对象。

- (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. 当用户点击self.dateField时,我的CustomPickerView会很好地弹出来代替标准键盘。

The problem is when the user taps the Done button from my CustomPickerView class, the buttonDonePush action does not fire. 问题是,当用户从我的CustomPickerView类中单击“完成”按钮时,buttonDonePush操作不会触发。

This answer can be considered as the iOS companion to a similar solution I offered recently for iOSX: 这个答案可以看作是我最近为iOSX提供的类似解决方案的iOS伴侣:

Interface-Builder: "combine" NSView-class with .xib Interface-Builder:与.xib结合使用NSView类

Your arrangement is thus: 因此,您的安排是:

  • Mainstoryboard.storyboard Mainstoryboard.storyboard
  • MyViewController.h MyViewController.h
  • MyViewController.m MyViewController.m

  • CustomPickerView.xib CustomPickerView.xib

  • CustomPickerView.h CustomPickerView.h
  • CustomPickerView.m CustomPickerView.m

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. 您想将customPickerView用作MyViewController.view的子视图,并希望能够从包含的上下文中访问其控件。

In your example you are creating the customPickerView in code, but another useful scenario is to add it to the storyboard in Interface Builder. 在您的示例中,您正在代码中创建customPickerView,但另一个有用的方案是将其添加到Interface Builder中的情节提要中。 This solution will work for both scenarios. 该解决方案适用于两种情况。

In CustomViewPicker.h 在CustomViewPicker.h中

  • declare IBOutlets for your interface elements. 为您的接口元素声明IBOutlets。 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. 您已经为datePicker和doneButton完成了此操作,但是还需要将UIView的IBOutlet用作这些项目的包含视图。

     @property (strong, nonatomic) IBOutlet UIView* view; 

In CustomViewPicker.xib 在CustomViewPicker.xib中

  • Set the file's owner class to CustomViewPicker in the Identity Inspector. 在Identity Inspector中将文件的所有者类设置为CustomViewPicker。
  • Set the top-level view in the xib to the defaul UIView class ( NOT CustomViewPicker). 将xib中的顶级视图设置为默认的UIView类( 不是 CustomViewPicker)。
  • Connect your IBOutlets from the file's owner: view , datePicker , doneButton to their respective IB objects 将您的IBOutlet从文件的所有者: viewdatePickerdoneButton到它们各自的IB对象
  • Connect your IBAction from the file's owner: buttonDonePush to the doneButton IB object 将IBAction从文件所有者连接: buttonDonePushdoneButton IB对象

In CustomViewPicker.m: 在CustomViewPicker.m中:

- (id)initWithFrame:(CGRect)frame
{
    //called when initialising in code
    self = [super initWithFrame:frame];
    if (self) {
        [self initialise];
    }
    return self;
}

  - (void)awakeFromNib
  {
      //called when loading from IB/Storyboard
      [self initialise];
  }

- (void) initialise
{
    NSString* nibName = NSStringFromClass([self class]);
    if ([[NSBundle mainBundle] loadNibNamed:nibName
                                      owner:self
                                    options:nil]) {
        [self.view setFrame:[self bounds]];
        [self addSubview:self.view];
    }

}
-(void) buttonDonePush:(id)sender
{
   //button push actions
}

If you want to initialise in code (as you have done), your MyViewController would contain something like this: 如果要初始化代码(如已完成),则MyViewController将包含以下内容:

- (void)viewDidLoad
{
    [super viewDidLoad];
    CGRect frame = CGRectMake(0, 50, 320, 300);
    self.customPickerView=[[CustomPickerView alloc] initWithFrame:frame];

    self.customPickerView.datePicker.datePickerMode=UIDatePickerModeTime;
    self.dateField.inputView=self.customPickerView;
}

[ edit removed this redundant line: [self.view addSubview:self.customPickerView]; [ 编辑删除了这条多余的线: [self.view addSubview:self.customPickerView]; ] ]

Alternatively you can create your CustomPickerView - and set it's frame - directly in the storyboard. 或者,您可以直接在情节提要中创建CustomPickerView并设置其框架。 Just add a custom view to your MyViewController's storyboard scene, and change it's class to CustomPickerView. 只需将自定义视图添加到MyViewController的故事板场景中,然后将其类更改为CustomPickerView。 Link it to your self.customPickerView IBOutlet. 将其链接到您的self.customPickerView IBOutlet。

In this case initWithFrame does not get called, but awakeFromNib is invoked when MyViewController loads it's CustomPickerView subview. 在这种情况下,不会调用initWithFrame ,但是当MyViewController加载其CustomPickerView子视图时,将调用awakeFromNib Your MyViewController's viewDidLoad would then look like this: 然后,您的MyViewController的viewDidLoad将如下所示:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.customPickerView.datePicker.datePickerMode=UIDatePickerModeTime;
    self.dateField.inputView=self.customPickerView;
}

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). 如果要从customPickerView中获取按钮按下操作,则可以考虑使用委托,与使用NSNotification相比,委托可以更加独立(但此问题超出了您的原始问题)。

EDIT: 编辑:

An answer above pointed this out, but in the init method you are setting self, but this happens before self is ever initialized. 上面的答案指出了这一点,但是在init方法中,您设置了self,但是这在对self进行初始化之前就发生了。 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: 在控制此自定义视图部署的类中:

//to invoke your view
CustomPickerView *myView;
NSArray *xibContents = [[NSBundle mainBundle]loadNibNamed:@"CustomPickerView" owner:nil options:nil];
for (id xibObject in xibContents) {
    if ([xibObject isKindOfClass:[CustomPickerView class]]) {
        myView = (CustomPickerView *)xibObject;
        break;
    }
}
//now *myView is instantiated as your custom picker view
//do what you want here, add to subview, set frame, etc

In the CustomPickerView.m file, remove the init method. 在CustomPickerView.m文件中,删除init方法。

PREVIOUS ANSWER: 上一个答案:

You are using NSNotificationCenter in this implementation. 您正在此实现中使用NSNotificationCenter。 When a user touches the done button, an NSNotification is posted. 当用户触摸完成按钮时,将发布NSNotification You must explicitly "opt in" and "listen" for these notifications. 您必须明确地“选择加入”和“收听”这些通知。 You do that by registering with the notification center. 您可以通过在通知中心注册来实现。

In viewDidLoad: 在viewDidLoad中:

 [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(receivedNotification:) 
    name:@"CustomPickerViewDoneButtonPush"
    object:nil];

Then you need to implement the selector you specified up there: 然后,您需要实现在此指定的选择器:

-(void)receivedNotification:(NSNotification *)note {
    NSDictionary *obj = [note object];
    NSLog(@"%@",obj);
    //dismiss the date picker here...
    //etc...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM