在重写的类方法中调用 super

发布于 2024-10-05 21:08:33 字数 516 浏览 8 评论 0原文

我想通过这样的类别向 UIButton 类添加一个新的自定义 UIButtonType

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface UIButton (Custom)

+ (id)buttonWithType:(UIButtonType)buttonType;

@end

Is it possible to get the super implementation of that overrided方法不知何故?

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

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

I want to add a new custom UIButtonType to the UIButton class via a category like so:

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface UIButton (Custom)

+ (id)buttonWithType:(UIButtonType)buttonType;

@end

Is it possible to get the super implementation of that overridden method somehow?

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

The code above is not valid since super refers to UIControl in this context.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

-小熊_ 2024-10-12 21:08:34

您可以在运行时用您自己的自定义方法替换该方法,如下所示:

#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 子类化。

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

You can replace the method at runtime with your own custom method like so:

#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);
}

Be careful how you use this, remember that it replaces the default implementation for every single UIButton your app uses. Also, it does override +load, so it may not work for classes that already have a +load method and rely on it.

In your case, you may well be better off just subclassing UIButton.

Edit: As Tyler notes below, because you have to use a class level method to make a button this may be the only way to override creation.

夜吻♂芭芘 2024-10-12 21:08:34

Jacob 有一个很好的观点,即类别方法与子类方法的行为不同。 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 初始化方法,因此子类实际上没有办法实例化自身并正确初始化为 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 类参考

Jacob has a good point that category methods act differently than subclass methods. Apple strongly suggests that you only provide category methods that are entirely new, because there are multiple things that can go wrong otherwise - one of those being that defining a category method basically erases all other existing implementations of the same-named method.

Unfortunately for what you're trying to do, UIButton seems to be specifically designed to avoid subclassing. The only sanctioned way to get an instance of a UIButton is through the constructor [UIButton buttonWithType:]. The problem with a subclass like Jacob suggests (like this):

@implementation MyCustomButton 

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

@end

is that the type returned by [MyCustomButton buttonWithType:] will still be a UIButton, not MyCustomButton. Because Apple hasn't provided any UIButton init methods, there's not really a way for a subclass to instantiate itself and be properly initialized as a UIButton.

If you want some customized behavior, you can create a custom UIView subclass that always contains a button as a subview, so that you can take advantage of some of UIButton's functionality.

Something like this:

@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

If you want the button to do different things depending on more complex user interactions, you can make more calls to [UIButton addTarget:action:forControlEvents:] for different control events.

Reference: Apple's UIButton class reference

梦年海沫深 2024-10-12 21:08:34

不,当您使用类别来增强类的功能时,这是不可能的,您不是扩展该类,您实际上完全覆盖了现有方法,您完全失去了原始方法。像风一样消失了。

如果您创建 UIButton 的子类,那么这是完全可能的:

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface MyCustomButton : UIButton {}

@end

@implementation MyCustomButton 

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

@end

No, this is not possible when you use a category to augment a class' functionality, you are not extending the class, you are actually wholly overriding the existing method, you lose the original method completely. Gone like the wind.

If you create a subclass of UIButton, then this is totally possible:

enum {
    UIButtonTypeMatteWhiteBordered = 0x100
};

@interface MyCustomButton : UIButton {}

@end

@implementation MyCustomButton 

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

@end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文