3

我想通过这样的类别UIButtonTypeUIButton类添加一个新的自定义:

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface UIButton (Custom)

+ (id)buttonWithType:(UIButtonType)buttonType;

@end

是否有可能以super某种方式实现该覆盖方法?

+ (id)buttonWithType:(UIButtonType)buttonType {
    return [super buttonWithType:buttonType];
}

上面的代码无效,因为在此上下文中super引用。UIControl

4

3 回答 3

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,因此它可能不适用于已经具有 +load 方法并依赖它的类。

在您的情况下,您最好只继承 UIButton。

编辑:正如泰勒在下面指出的那样,因为您必须使用类级别的方法来制作按钮,这可能是覆盖创建的唯一方法。

于 2010-12-03T18:46:51.037 回答
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
于 2010-12-03T16:40:39.463 回答
3

Jacob 有一个很好的观点,即类别方法与子类方法的作用不同。Apple 强烈建议您只提供全新的类别方法,因为否则可能会出错 - 其中之一是定义类别方法基本上会删除同名方法的所有其他现有实现。

不幸的是,对于您正在尝试做的事情,UIButton似乎是专门为避免子类化而设计的。获得 a 实例的唯一认可方法UIButton是通过构造函数[UIButton buttonWithType:]。像 Jacob 这样的子类的问题表明(像这样):

@implementation MyCustomButton 

+ (id)buttonWithType:(UIButtonType)buttonType {
  return [super buttonWithType:buttonType]; //super here refers to UIButton
}

@end

是返回的类型[MyCustomButton buttonWithType:]仍然是 a UIButton而不是 MyCustomButton。因为 Apple 没有提供任何UIButtoninit 方法,所以子类实际上没有办法实例化自身并正确初始化为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:]针对不同的控件事件进行更多调用。

参考:Apple 的 UIButton 类参考

于 2010-12-03T21:05:33.550 回答