关于ios:从View中触发UIViewController中的方法

Trigger a method in UIViewController from its View

我有一个UIViewController和它的UIView,其中包含一个UIButton。我想在UIViewControlleron button click事件中触发一个方法。保留对UIViewController的引用似乎不是一个好主意,如下链接所示:从uiview转到uiviewcontroller?

所以我想用一个代表来实现这个目标。关于如何实现这一点有什么提示吗?


你可以这样做

自定义视图

1
2
3
4
5
6
7
8
9
10
11
12
#import <UIKit/UIKit.h>
@protocol CustomViewDelegate <NSObject>

 -(void)didButtonPressed;

@end

 @interface CustomView : UIView

  @property (assign) id<CustomViewDelegate> delegate;

@end

客户视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import"CustomView.h"
@implementation CustomView

- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
    // Initialization code
    self.backgroundColor = [UIColor whiteColor];

    //[self addSubview:titleLbl];
    UIButton *button= [UIButton buttonWithType:UIButtonTypeRoundedRect];
    button.frame = CGRectMake(100, 100, 100, 50);
    [button addTarget:self.delegate action:@selector(didButtonPressed) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"pressMe" forState:UIControlStateNormal];
    [self addSubview:button];


}
return self;
}

在你的视图控制器中。

1
2
3
4
5
6
7
8
-(void)loadView
 {
  [super loadView];
  CustomView *view = [[CustomView alloc]initWithFrame:self.view.bounds];
  view.delegate = self;
  [self.view addSubview:view];

 }


这就是构建响应链的目的。当您在按钮中添加目标时,只需为目标提供nil

1
2
3
[mySpecialButton addTarget:nil
                 action:@selector(mySpecialButtonTapped:)
                 forControlEvents:UIControlEventTouchUpInside];

nil目标基本上是指"将mySpecialButtonTapped:发送到响应链中能够处理它的任何对象"。

现在,您可以在响应器链中的任何位置处理此选择器,其中包括按钮本身、它的包含视图、它的包含视图控制器、ui应用程序,最后是您的appdelegate。只需将此方法放在最适合您需要的对象中:

1
2
3
- (void)mySpecialButtonTapped:(id)sender {
    NSLog("My special button was tapped!");
}

如果您只想使消息冒泡,则不需要委托或回调块(如接受的答案中所示)。


我猜你期望一些更基本的东西,然后把一些按钮动作传递给控制器。在模型/视图/控制器协作的情况下,我总是遵循MVC模式。它解决了你和其他许多问题。我想分享我的经历。

  • 将控制器从视图和模型中分离出来:不要将所有的"业务逻辑"放到视图相关的类中;这使得代码非常不可用。使控制器类承载此代码,但确保控制器类不会对表示做出太多假设。
  • 使用@protocol定义回调API,如果不是所有方法都是必需的,则使用@optional定义回调API。
  • 对于视图,定义类似于Protocol的协议(例如newsViewProtocol)。对于控制器,定义类似于Delegate的委托(例如newsViewDelegate)和类似于DataSource的数据源(例如newsViewDataSource)。将所有@protocols保存在一个名为Protocol.h的单独文件中(例如newsviewprotocol.h)
  • 简短的例子:

    newsview.h的内容

    1
    2
    3
    4
    5
    6
    7
    8
    //
    // NewsView.h
    @interface NewsView : UIView <NewsViewProtocol> {
    @protected
         NSObject* delegate_;
         NSObject* dataSource_;
    }
    @end

    新闻总监.h和.m的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    //
    // NewsController.h
    @interface NewsController : UIViewController <NewsViewDataSource, NewsViewDelegate> {
    }
    @property (nonatomic, weak) UIView<NewsViewProtocol>* customView;
    @end

    @implementation NewsController
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.customView = (UIView<NewsViewProtocol>*)self.view;
        [self.customView setDelegate:self];
        [self.customView setDataSource:self];
    }
    @end

    newsviewprotocol.h的内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    //
    // NewsViewProtocol.h
    @protocol NewsViewProtocol;

    @protocol NewsViewDelegate<NSObject>
    @optional
    - (void)someAction;
    - (void)newsView:(UIView<NewsViewProtocol>*)newsView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
    @end

    @protocol NewsViewDataSource<NSObject>
    @required
    - (id)newsView:(UIView<NewsViewProtocol>*)newsView itemAtIndexPath:(NSIndexPath *)indexPath;
    - (NSInteger)numberOfItemsInNewsView:(UIView<NewsViewProtocol>*)newsView section:(NSInteger)section;
    - (BOOL)newsView:(UIView<NewsViewProtocol>*)newsView shouldDisplaySection:(NSInteger)section;
    @end

    @protocol NewsViewProtocol<NSObject>
    @required

    //Never retain delegate instance into implementation of this method
    - (void)setDelegate:(NSObject<NewsViewDelegate>*)delegate;
    //Never retain delegate instance into implementation of this method
    - (void)setDataSource:(NSObject<NewsViewDataSource>*)dataSource;
    - (void)reload;
    @end

    你可以认为这是多余的。在简单视图控制器中,是的。但是,如果您开发具有大量数据的非常复杂的屏幕,那么它会给您带来以下优势:

    • 帮助您区分视图和控制器之间的责任。
    • 保持代码清晰。
    • 使代码更加可重用。

    在Xcode中生活很容易。

    在一开始,请确保XIB视图(其中包含按钮的视图)与Right ViewController类相关联。它可以是新项目或自定义项目附带的默认ViewController类。

    在这之后,魔术就来了!将视图分成两个面板。目标是查看XIB和ViewController代码(.m文件)。现在,按下键盘的控制键并将ui按钮拖到代码上。选择IBaction。它会产生一些你可以用其他语言称之为"倾听者"的东西。转到视图控制器的核心代码并完成该方法!

    很容易!玩得开心:


    您可以尝试以下操作:

    1
    [yourButton addTarget:self action:@selector(yourButtonAction:) forControlEvents:UIControlEventTouchUpInside];

    在选择器中指定操作

    1
    2
    3
    - (IBAction)yourButtonAction:(id)sender {
         //Action to perform
    }

    在myviewcontroller.m中以编程方式添加按钮

    1
    2
    3
    4
    UIView *yourView = [[UIView alloc] init];
    UIButton *yourButton = [[UIButton alloc] initWithFrame:CGRectMake(0,0,100,21)];
    [yourButton addTarget:self action:@selector(yourMethod) forControlEvents:UIControlEventTouchDown];
    [yourView addSubview:yourButton];

    更多信息在这里。


    你不需要委托-这就是uibuttons的用途。只需控制单击并从按钮拖动到uiviewcontroller的.m文件。这将创建一个新方法。从那里,您可以调用您编写的方法,也可以复制粘贴到新方法中。