在主视图控制器中使用自定义单元格内UIButton的IBAction

7
我已经创建了一个自定义的单元格,它有自己的 .m、.h 和 .xib 文件。在这个单元格中,我添加了一个 UIButton 到 IB 中。
我可以在这个自定义单元格的 .m 文件中接收到来自 UIButton 的 IBAction,但实际上,我希望将该按钮按下事件转发到主视图的 .m 文件中,该视图托管了表格(以及自定义单元格),并在那里使用一个动作。
我花了过去 4 个小时尝试各种方法来做到这一点 - 我应该使用 NSNotificationCenter 吗?(我经常尝试通知但无法使其工作,也不确定是否应该坚持这样做)

我认为NSNotificationCenter是一个合理的策略。您是否没有接收到按钮操作方法发送的通知或其他问题? - Phillip Mills
我也是这么想的 - 我觉得我还没有掌握实现它们的诀窍...需要更多的练习。我现在可以让它们在同一个视图中工作,但是当我尝试不同的视图时仍然会出现异常...我们会成功的。 - James Morris
这是一个非常完整的关于创建和使用委托协议的解释。http://www.dosomethinghere.com/2009/07/18/setting-up-a-delegate-in-the-iphone-sdk/ - MystikSpiral
委托也可以起作用。区别在于耦合方面微妙的差异。委托有点松散,因为需要处理辅助的对象被告知从哪里获取它,但对委托对象的其他了解很少。通知甚至更加松散,通知对象只是断言发生了某些事情,并将其留给未知的侦听器是否响应。这可能是一种哲学选择,除非您需要支持多个侦听器。 - Phillip Mills
5个回答

9
您需要在单元格的.h文件中使用委托。 像这样声明委托:
@class MyCustomCell;
@protocol MyCustomCellDelegate
- (void) customCell:(MyCustomCell *)cell button1Pressed:(UIButton *)btn;
@end

然后声明字段和属性。
@interface MyCustomCell:UItableViewCell {
    id<MyCustomCellDelegate> delegate;
}

@property (nonatomic, assign) id<MyCustomCellDelegate> delegate;

@end

在 .m 文件中

@synthesize delegate;

在按钮方法中
- (void) buttonPressed {
    if (delegate && [delegate respondToSelector:@selector(customCell: button1Pressed:)]) {
        [delegate customCell:self button1Pressed:button];
    }
}

您的视图控制器必须像这样采用此协议

.h文件

#import "MyCustomCell.h"

@interface MyViewController:UIViewController <MyCustomCellDelegate>
.....
.....
@end

在cellForRow:方法的.m文件中,您需要将delegate属性添加到单元格中。
cell.delegate = self;

最后,您需要实现协议中的方法。

- (void) customCell:(MyCustomCell *)cell button1Pressed:(UIButton *)btn {

}

非常抱歉我的英语和代码,我是在没有XCODE的情况下从我的电脑上编写的。


  • (void) buttonPressed { if (delegate && [delegate respondToSelector:@selector(customCell: button1Pressed:)]) { [delegate customCell:self button1Pressed:button]; } }
在 [delegate customCell:self button1Pressed:button]; 中,你从哪里获取 "button"?当我在控制器中添加该方法时,展示另一个视图控制器的示例代码是什么?谢谢。
- zramled
要呈现另一个视图控制器,您可以使用 [self presentViewController: animated: completion:] 或 [self.navigationController pushViewController: animated:]。 - Moonkid
@Moonkid,这个问题有Swift的答案吗? - Runeaway3
@AlekPiasecki 你好,Swift中使用闭包比使用代理更容易,但当然你也可以使用代理。Swift书中有一章关于协议的内容。 https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html - Moonkid

1

我遇到相同的问题,通过对单元格进行子类化并将按钮放置为Outlets解决了该问题,并使用从模型填充单元格的数据方法,同时使用返回当前查看的单元格的方法。

例如,如果你有一个Person类,每个人都有姓名、姓氏和一些朋友。每当你点击单元格中的一个按钮时,特定人的朋友数量会增加1。

_______________DATA SOURCE___________________________
#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *comment;
@property (nonatomic) NSInteger numberOfFriends;


+(instancetype)personWithName:(NSString *)aName Surname:(NSString *)aSurname;

@end

#import "Person.h"

@implementation Person

+(instancetype)personWithName:(NSString *)aName Surname:(NSString *)aSurname{

    Person *person = [[Person alloc] init];
    [person setName:aName];
    [person setSurname:aSurname];
    [person setNumberOfFriends:0];

    return person;
}

@end

_____________________PERSON CELL________________________

#import <UIKit/UIKit.h>

@interface PersonCell : UITableViewCell

@property (strong, nonatomic) IBOutlet UILabel *friendsNum;
@property (strong, nonatomic) IBOutlet UIButton *friendsBtn;
@property (strong, nonatomic) IBOutlet UILabel *nameLabel;
@property (strong, nonatomic) IBOutlet UILabel *surnameLabel;


@end

个人而言,我创建了一个私有的NSArray来保存我的Person对象的名称,还创建了一个私有的NSMutableDictionary来保存我的Person对象,并将键设置为人名。

_____________________PERSON TABLE VIEW________________________    
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    PersonCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    NSString *name = [peopleNames objectAtIndex:indexPath.row];
    Person *person = [people objectForKey:name];

    if(cell == nil)
    {
        cell = [[PersonCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }

    // Configure the cell...
    cell.nameLabel.text = person.name;
    cell.surname.Label.text = person.surname

    [cell.friendsButton addTarget:self action:@selector(moreFriends:) forControlEvents:UIControlEventTouchUpInside];

    cell.friendsNum.text = [NSString stringWithFormat:@"%i", person.numberOfFriends];

    return cell;
}

- (IBAction)moreFriends:(id)sender {
    UIButton *btn = (UIButton *)sender;
    PersonCell *cell = [self parentCellForView:btn];
    Person *person = [people objectForKey:cell.nameLabel.text];
    person.numberOfFriends++;
    [self.tableView reloadData];
}

-(PersonCell *)parentCellForView:(id)theView
{
    id viewSuperView = [theView superview];
    while (viewSuperView != nil) {
        if ([viewSuperView isKindOfClass:[PersonCell class]]) {
            return (PersonCell *)viewSuperView;
        }
        else {
            viewSuperView = [viewSuperView superview];
        }
    }
    return nil;
}

0

0
为什么不为您的自定义单元格创建一个委托(使用@protocol)呢?然后,您可以将主视图指定为每个单元格的委托,并适当地处理操作。

我觉得我最好研究一下委托...我完全不知道该怎么做!! - James Morris

0
你可能想在你的视图控制器中为按钮添加一个选择器,该视图控制器包含你的表格视图。
在你的 cellForIndexPath 函数中。
[yourCell.button addTarget:self action:@selector(customActionPressed:) forControlEvents:UIControlEventTouchDown];

然后在你的“customActionPressed:(id) sender”方法中处理按钮点击事件。

    //Get the superview from this button which will be our cell
UITableViewCell *owningCell = (UITableViewCell*)[sender superview];

//From the cell get its index path.
NSIndexPath *pathToCell = [myTableView indexPathForCell:owningCell];

    //Do something with our path

除非您尚未列出更多因素,否则这可能是对您更好的解决方案。

我有一个教程,可能会更详细地解释http://www.roostersoftstudios.com/2011/05/01/iphone-custom-button-within-a-uitableviewcell/


谢谢,其实我已经知道了按钮的路径,因为我正在使用选择的单元格来选择一个plist的方法(有点粗糙但效果很好)。不过我会尝试你的教程,看看能否用不同的方式解决我的问题。 - James Morris
听起来不错。如果您知道索引并且可以以某种方式使用它来获取所需的数据,则可能已经拥有在拥有视图控制器中执行操作所需的所有内容。祝好运。 - rooster117
同时,看看别人建议使用代理也是一个非常好的想法。这是我以前制作的另一个教程,可以用来学习:[链接]http://www.roostersoftstudios.com/2011/04/12/simple-delegate-tutorial-for-ios-development/ - rooster117

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接