对于特定代码类别,我有以下代码:类别正在实现一个方法,该方法也将被其主要类实现。
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
return [self aCustomFontOfSize:fontSize];
}
对于特定代码类别,我有以下代码:类别正在实现一个方法,该方法也将被其主要类实现。
+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
return [self aCustomFontOfSize:fontSize];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
// do your override
#pragma clang diagnostic pop
我在这里找到了相关信息:http://www.cocoabuilder.com/archive/xcode/313767-disable-warning-for-override-in-category.html分类(Category)允许你为现有的类添加新的方法。如果你想要重新实现一个已经存在于类中的方法,通常情况下你会创建一个子类而不是一个分类。
苹果公司文档:自定义现有类
如果一个分类中声明的方法和原始类中已经存在的方法名称相同,或者和同一类(甚至是超类)上另一个分类中的方法名称相同,那么在运行时使用哪个方法实现是没有定义的。
在同一个类中拥有两个具有完全相同签名的方法会导致不可预测的行为,因为每个调用者不能指定他们所需要的实现。
因此,如果你想要为类提供新的唯一方法名,应该使用一个分类;如果你想要改变一个类中一个已存在的方法的行为,则应该使用一个子类。
更好的替代方案(查看bneely的答案以了解为什么这个警告会拯救你于水深火热之中)是使用方法交换。通过使用方法交换,您可以替换类别中的现有方法,而无需关注“谁赢”,同时保留调用旧方法的能力。秘密是给覆盖一个不同的方法名称,然后使用运行时函数交换它们。
#import <objc/runtime.h>
#import <objc/message.h>
void MethodSwizzle(Class c, SEL orig, SEL new) {
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
然后定义你的自定义实现:
+ (UIFont *)mySystemFontOfSize:(CGFloat)fontSize {
...
}
用你自己的实现覆盖默认实现:
MethodSwizzle([UIFont class], @selector(systemFontOfSize:), @selector(mySystemFontOfSize:));
在你的代码中尝试这个:
+(void)load{
EXCHANGE_METHOD(Method1, Method1Impl);
}
更新2:添加此宏
#import <Foundation/Foundation.h>
#define EXCHANGE_METHOD(a,b) [[self class]exchangeMethod:@selector(a) withNewMethod:@selector(b)]
@interface NSObject (MethodExchange)
+(void)exchangeMethod:(SEL)origSel withNewMethod:(SEL)newSel;
@end
#import <objc/runtime.h>
@implementation NSObject (MethodExchange)
+(void)exchangeMethod:(SEL)origSel withNewMethod:(SEL)newSel{
Class class = [self class];
Method origMethod = class_getInstanceMethod(class, origSel);
if (!origMethod){
origMethod = class_getClassMethod(class, origSel);
}
if (!origMethod)
@throw [NSException exceptionWithName:@"Original method not found" reason:nil userInfo:nil];
Method newMethod = class_getInstanceMethod(class, newSel);
if (!newMethod){
newMethod = class_getClassMethod(class, newSel);
}
if (!newMethod)
@throw [NSException exceptionWithName:@"New method not found" reason:nil userInfo:nil];
if (origMethod==newMethod)
@throw [NSException exceptionWithName:@"Methods are the same" reason:nil userInfo:nil];
method_exchangeImplementations(origMethod, newMethod);
}
@end
您可以使用方法交换来抑制此编译器警告。以下是我为UITextField中的自定义背景与UITextBorderStyleNone一起绘制边距实现方法交换的方式:
#import <UIKit/UIKit.h>
@interface UITextField (UITextFieldCatagory)
+(void)load;
- (CGRect)textRectForBoundsCustom:(CGRect)bounds;
- (CGRect)editingRectForBoundsCustom:(CGRect)bounds;
@end
#import "UITextField+UITextFieldCatagory.h"
#import <objc/objc-runtime.h>
@implementation UITextField (UITextFieldCatagory)
+(void)load
{
Method textRectForBounds = class_getInstanceMethod(self, @selector(textRectForBounds:));
Method textRectForBoundsCustom = class_getInstanceMethod(self, @selector(textRectForBoundsCustom:));
Method editingRectForBounds = class_getInstanceMethod(self, @selector(editingRectForBounds:));
Method editingRectForBoundsCustom = class_getInstanceMethod(self, @selector(editingRectForBoundsCustom:));
method_exchangeImplementations(textRectForBounds, textRectForBoundsCustom);
method_exchangeImplementations(editingRectForBounds, editingRectForBoundsCustom);
}
- (CGRect)textRectForBoundsCustom:(CGRect)bounds
{
CGRect inset = CGRectMake(bounds.origin.x + 10, bounds.origin.y, bounds.size.width - 10, bounds.size.height);
return inset;
}
- (CGRect)editingRectForBoundsCustom:(CGRect)bounds
{
CGRect inset = CGRectMake(bounds.origin.x + 10, bounds.origin.y, bounds.size.width - 10, bounds.size.height);
return inset;
}
@end
分类是一件好事,但它们可能会被滥用。 在编写分类时,原则上不应重新实现现有的方法。 这样做可能会导致奇怪的副作用,因为您现在正在重写另一个类依赖的代码。您可能会破坏已知的类,并最终使调试器失效。 这只是糟糕的编程。
如果您需要这样做,确实应该对其进行子类化。
然后是交换建议,对我来说完全不行。
在运行时进行交换是完全不可取的。
你想让香蕉看起来像橙子,但只在运行时? 如果你想要一个橙子,那就写一个橙子。
不要让香蕉看起来和行动像橙子。 更糟糕的是:不要把你的香蕉变成一个秘密特工,默默地支持橙子破坏全球的香蕉。
天啊!
super
。 - Alan Zeino