我想通过类似的类别向UIButtonType
课程添加新的自定义UIButton
:
enum {
UIButtonTypeMatteWhiteBordered = 0x100
};
@interface UIButton (Custom)
+ (id)buttonWithType:(UIButtonType)buttonType;
@end
是否有可能以某种方式获得该重写方法的super
实现?
+ (id)buttonWithType:(UIButtonType)buttonType {
return [super buttonWithType:buttonType];
}
上述代码无效,因为super
在此上下文中引用UIControl
。
答案 0 :(得分:7)
您可以在运行时使用自己的自定义方法替换方法,如下所示:
#import <objc/runtime.h>
@implementation UIButton(Custom)
// At runtime this method will be called as buttonWithType:
+ (id)customButtonWithType:(UIButtonType)buttonType
{
// ---Add in custom code here---
// This line at runtime does not go into an infinite loop
// because it will call the real method instead of ours.
return [self customButtonWithType:buttonType];
}
// Swaps our custom implementation with the default one
// +load is called when a class is loaded into the system
+ (void) load
{
SEL origSel = @selector(buttonWithType:);
SEL newSel = @selector(customButtonWithType:);
Class buttonClass = [UIButton class];
Method origMethod = class_getInstanceMethod(buttonClass, origSel);
Method newMethod = class_getInstanceMethod(buttonClass, newSel);
method_exchangeImplementations(origMethod, newMethod);
}
请注意如何使用它,请记住它取代了您的应用使用的每个UIButton的默认实现。此外,它确实覆盖+加载,因此它可能不适用于已经有+ load方法且依赖它的类。
在你的情况下,你可能最好只是继承UIButton。
编辑:正如Tyler在下面所说,因为您必须使用类级方法来创建按钮,这可能是覆盖创建的唯一方法。
答案 1 :(得分:3)
不,当您使用类别来扩充类的功能时,这是不可能的,您不是扩展类,您实际上完全覆盖现有方法,您将丢失原始方法<强>完全即可。像风一样。
如果你创建了UIButton
的子类,那么这是完全可能的:
enum {
UIButtonTypeMatteWhiteBordered = 0x100
};
@interface MyCustomButton : UIButton {}
@end
@implementation MyCustomButton
+ (id)buttonWithType:(UIButtonType)buttonType {
return [super buttonWithType:buttonType]; //super here refers to UIButton
}
@end
答案 2 :(得分:3)
雅各布有一个很好的观点,即类别方法与子类方法的行为不同。 Apple强烈建议您只提供全新的类别方法,因为有许多事情可能会出错 - 其中一个定义类别方法基本上会删除同名方法的所有其他现有实现。
不幸的是,对于您要做的事情,UIButton
似乎是专门为避免子类化而设计的。获取UIButton
实例的唯一受制裁方法是通过构造函数[UIButton buttonWithType:]
。像Jacob这样的子类的问题表明(像这样):
@implementation MyCustomButton
+ (id)buttonWithType:(UIButtonType)buttonType {
return [super buttonWithType:buttonType]; //super here refers to UIButton
}
@end
[MyCustomButton buttonWithType:]
返回的类型仍然是UIButton
,不是 MyCustomButton
。因为Apple没有提供任何UIButton
init方法,所以实际上没有一种方法可以让子类实例化自己并正确初始化为UIButton
。
如果您想要一些自定义行为,您可以创建一个自定义UIView
子类,该子类始终包含一个按钮作为子视图,以便您可以利用UIButton
的某些功能。
这样的事情:
@interface MyButton : UIView {}
- (void)buttonTapped;
@end
@implementation MyButton
-(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = self.bounds;
[button addTarget:self action:@selector(buttonTapped)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void)buttonTapped {
// Respond to a button tap.
}
@end
如果您希望按钮根据更复杂的用户互动执行不同的操作,则可以针对不同的控制事件拨打[UIButton addTarget:action:forControlEvents:]
的更多电话。