子类化UIButton以添加属性

35
我想通过继承UIButton类来添加一些我需要的属性(不是方法...只有属性)。
以下是我的子类代码:
//.h-----------------------
@interface MyButton : UIButton{
    MyPropertyType *property;
}

@property (nonatomic,retain) MyPropertyType *property;
@end

//.m--------------------------
@implementation MyButton
@synthesize property;

@end

这是我如何使用该类:

MyButton *btn = ((MytButton *)[MyButton buttonWithType:UIButtonTypeRoundedRect]);
btn.property = SomeDataForTheProperty;

我从哪里获取到这个错误:

 -[UIRoundedRectButton setProperty:]: unrecognized selector sent to instance 0x593e920

因此,从ButtonWithType中我获得了一个UIRoundedRectButton对象,而且(Mybutton *)不能将其强制转换。 我该怎么做才能获得一个MyButton对象? 是否-init是唯一的解决方案?

谢谢!


我可以确认使用init方法可以工作,但是我得到的是一个UIButtonTypeCustom而不是roundRect。 - MatterGoal
在iOS6和iOS7中,对按钮进行子类化对我有效,我想知道这在早期的操作系统中是否存在问题。 - Skotch
3个回答

88

尝试使用具有关联引用的类别。这样做更加简洁,并且将适用于所有UIButton实例。

UIButton+Property.h

#import <Foundation/Foundation.h>

@interface UIButton(Property)

@property (nonatomic, retain) NSObject *property;

@end

UIButton+Property.m

#import "UIButton+Property.h"
#import <objc/runtime.h>

@implementation UIButton(Property)

static char UIB_PROPERTY_KEY;

@dynamic property;

-(void)setProperty:(NSObject *)property
{
    objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

-(NSObject*)property
{
    return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY);
}

@end

//使用示例

#import "UIButton+Property.h"

...

UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1.property = @"HELLO";
NSLog(@"Property %@", button1.property);
button1.property = nil;
NSLog(@"Property %@", button1.property);

1
您无需初始化它,地址就是关键。 - Joe
2
我并不认为这是一种干净的解决方案... 这只是一种hacky的解决方案。 - João Nunes
1
@JoãoNunes 你能解释一下一个文档完备的解决方案中有什么"hacky"的地方吗? - Joe
2
在UIButton的情况下,我认为这比子类化是一个更好的解决方案,因为在子类上调用buttonWithType:不会返回具有继承方法的对象。 - David John Smith
当然,你也必须子类化初始化方法!否则你只是创建了一个 UIButton,而不是创建一个不同的对象。 - João Nunes
显示剩余11条评论

12
你需要做的是:
MyButton *btn = [[MyButton alloc] init];

创建你的按钮。 buttonWithType:UIButtonTypeRoundedRect 只会创建UIButton对象。

=== 编辑 ===

如果您希望使用圆角矩形按钮,则建议按照以下步骤进行。基本上,我们只需创建一个具有所需属性的UIView,并将所需的按钮添加到该视图中。


.h

@interface MyButton : UIView
{
    int property;
}

@property int property;
@end

.m

的翻译是:

.m

@implementation MyButton
@synthesize property;

- (id)initWithFrame:(CGRect)_frame
{
    self = [super initWithFrame:_frame];
    if (self)
    {
        UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        btn.frame = self.bounds;
        [self addSubview:btn];
    }
    return self;
}

@end

使用方法:

MyButton *btn = [[MyButton alloc] initWithFrame:CGRectMake(0, 0, 200, 20)];
btn.property = 42;

[self.view addSubview:btn];


这个方法是否限制您只能使用UIButtonTypeCustom类型的按钮? - Joe
3
除非他通过属性公开btn,否则他无法访问任何按钮方法。 - Joe
@Joe:好的,它也可以被提升为属性。或者你可以隐藏一些UIButton功能。很棒的Facade,Wex。 - Dan Rosenstark

2

我的方案非常简单,只涉及少量库方法,无样板文件,并且每个要添加的属性只需要3行代码。下面添加了两个示例属性:startPoint和tileState。为了说明,这里是您需要添加的代码行,例如对于像tileState这样的属性:

//@property (assign, nonatomic) SCZTileState tileState; // tileState line 1 
//@property (assign, nonatomic) SCZTileState tileState; // tileState line 2 
//@dynamic tileState;                                   // tileState line 3

我在我的博客文章中详细介绍了这个功能的更多细节:子类化UIButton或者如何避免子类化并仍然获胜

UIButton+SCZButton.h

#import <UIKit/UIKit.h>

@interface UIButton (SCZButton)
@property (readwrite, nonatomic) id assocData;
@end

UIButton+SCZButton.m

//  UIButton+SCZButton.m
//  Copyright (c) 2013 Ooghamist LLC. All rights reserved.

#import "UIButton+SCZButton.h"
#import <objc/runtime.h>

@implementation UIButton (SCZButton)
- (id)assocData {
    id data = objc_getAssociatedObject(self, "SCZButtonData");
    return data;
}
- (void)setAssocData:(id)data {
    objc_setAssociatedObject(self, "SCZButtonData", data,  
                             OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

OOGTotallyTile.h

//  UIButton+OOGTotallyTile.m
//  Copyright (c) 2013 Ooghamist LLC. All rights reserved.
#import <UIKit/UIKit.h>
#import "UIButton+SCZButton.h"
#define kPointLabelTag 837459

typedef enum {
    SCZTileStatePlaced,
    SCZTileStateDropping,
    SCZTileStateDropped
} SCZTileState;

@interface SCZButtonData : NSObject
@property (assign, nonatomic) CGPoint startPoint;
@property (assign, nonatomic) SCZTileState tileState;   // tileState line 1
@end

@interface UIButton (OOGTotallyTile)
@property (readonly, nonatomic) SCZButtonData *buttonData;
@property (assign, nonatomic) CGPoint startPoint;
@property (assign, nonatomic) SCZTileState tileState;  // tileState line 2
@end

OOGTotallyTile.m

//  UIButton+OOGTotallyTile.m
//  Copyright (c) 2013 Ooghamist LLC. All rights reserved.

#import "OOGTotallyTile.h"

@implementation SCZButtonData
@end

@implementation UIButton (OOGTotallyTile)
@dynamic startPoint;
@dynamic tileState; // tileState line 3

- (SCZButtonData*)buttonData {
    if ( ! self.assocData) {
        self.assocData = [[SCZButtonData alloc] init];
    }
    return self.assocData;
}
- (id)forwardingTargetForSelector:(SEL)aSelector {
    id forwardingTarget = [super forwardingTargetForSelector:aSelector];
    if ( ! forwardingTarget) {
        return [self buttonData];
    }
    return forwardingTarget;
}
@end

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