súper llamada de método de clase reemplazado [duplicado]
-
30-09-2019 - |
Pregunta
Esta pregunta ya tiene una respuesta aquí:
Quiero añadir un nuevo UIButtonType
personalizado a la clase UIButton
a través de una categoría, así:
enum {
UIButtonTypeMatteWhiteBordered = 0x100
};
@interface UIButton (Custom)
+ (id)buttonWithType:(UIButtonType)buttonType;
@end
¿Es posible conseguir la aplicación super
de ese método reemplazado alguna manera?
+ (id)buttonWithType:(UIButtonType)buttonType {
return [super buttonWithType:buttonType];
}
El código anterior no es válida desde super
refiere a UIControl
en este contexto.
Solución
No, esto no es posible cuando se utiliza una categoría para aumentar una funcionalidad de clase, usted no es extendiéndose de la clase, en realidad está totalmente reemplazando el método existente, se pierde el método original < strong> completamente . Ido como el viento.
Si crea una subclase de UIButton
, entonces esto es totalmente posible:
enum {
UIButtonTypeMatteWhiteBordered = 0x100
};
@interface MyCustomButton : UIButton {}
@end
@implementation MyCustomButton
+ (id)buttonWithType:(UIButtonType)buttonType {
return [super buttonWithType:buttonType]; //super here refers to UIButton
}
@end
Otros consejos
Se puede sustituir el método en tiempo de ejecución con su propio método personalizado de este modo:
#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);
}
Tenga cuidado de cómo se utiliza esto, recuerde que sustituye a la aplicación por defecto para todos los usos UIButton sus aplicaciones. Además, lo hace anulación + carga, por lo que puede no funcionar para las clases que ya cuentan con un método de carga + y dependen de ella.
En su caso, es posible que así sea mejor simplemente la subclasificación UIButton.
Editar :. Como notas Tyler a continuación, ya que hay que utilizar un método de nivel de clase para hacer un botón que esto puede ser la única manera de creación de corrección
Jacob tiene un punto bueno que los métodos categoría actúan de manera diferente que los métodos de subclase. Manzana sugiere fuertemente que sólo se proporcionan métodos categoría que son completamente nuevo, porque hay varias cosas que pueden salir mal lo contrario -. Uno de los seres que la definición de un método categoría básicamente borra todas las demás implementaciones existentes del mismo nombre método
Por desgracia para lo que estamos tratando de hacer, UIButton
parece estar diseñado específicamente para evitar la subclasificación. La forma única sancionada para obtener una instancia de un UIButton
es a través de la [UIButton buttonWithType:]
constructor. El problema con una subclase como Jacob sugiere (como este):
@implementation MyCustomButton
+ (id)buttonWithType:(UIButtonType)buttonType {
return [super buttonWithType:buttonType]; //super here refers to UIButton
}
@end
es que el tipo devuelto por [MyCustomButton buttonWithType:]
seguirá siendo un UIButton
, no MyCustomButton
. Debido a que Apple no ha proporcionado ningún método init UIButton
, no hay realmente una manera para que una subclase crear una instancia de sí mismo y ser inicializado correctamente como UIButton
.
Si quieres algo de comportamiento personalizado, puede crear una subclase UIView
personalizado que siempre contiene un botón como subvista, de modo que usted puede tomar ventaja de algunas de las funciones de UIButton
.
Algo como esto:
@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
Si desea que el botón para hacer cosas diferentes en función de las interacciones del usuario más complejos, se puede hacer más llamadas a [UIButton addTarget:action:forControlEvents:]
para diferentes eventos de control.
Referencia: referencia de clase UIButton de Apple