Подавить предупреждение «Категория реализует метод, который также будет реализован его основным классом»

Мне было интересно, как подавить предупреждение:

  

Категория реализует метод, который также будет реализован   его основной класс.

У меня есть это для определенной категории кода:

+ (UIFont *)systemFontOfSize:(CGFloat)fontSize {
    return [self aCustomFontOfSize:fontSize];
}
96 голосов | спросил Doz 24 FebruaryEurope/MoscowbFri, 24 Feb 2012 05:14:12 +0400000000amFri, 24 Feb 2012 05:14:12 +040012 2012, 05:14:12

7 ответов


0

Категория позволяет добавлять новые методы в существующий класс. Если вы хотите переопределить метод, который уже существует в классе, вы обычно создаете подкласс вместо категории.

Документация Apple: Настройка существующих классов

  

Если имя метода объявлено в   Категория такая же, как метод в исходном классе, или метод в   другой категории того же класса (или даже суперкласса),   поведение не определено относительно того, какая реализация метода используется в   во время выполнения.

Два метода с одинаковой сигнатурой в одном и том же классе могут привести к непредсказуемому поведению, поскольку каждый вызывающий объект не может указать, какую реализацию он хочет.

Таким образом, вы должны либо использовать категорию и предоставить имена методов, которые являются новыми и уникальными для класса, либо подкласс, если вы хотите изменить поведение существующего метода в классе.

ответил bneely 24 FebruaryEurope/MoscowbFri, 24 Feb 2012 05:15:53 +0400000000amFri, 24 Feb 2012 05:15:53 +040012 2012, 05:15:53
0

Хотя все, что сказал Бнили, правильно, на самом деле оно не отвечает на ваш вопрос о том, как подавить предупреждение.

Если по какой-то причине вам нужен этот код (в моем случае у меня есть HockeyKit в моем проекте, и они переопределяют метод в категории UIImage [edit: это больше не так]), и вам нужно получить Для компиляции проекта вы можете использовать операторы #pragma, чтобы заблокировать предупреждение следующим образом:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"

// do your override

#pragma clang diagnostic pop

Я нашел информацию здесь: http: //www .cocoabuilder.com /архив /Xcode /313767-отключить предупреждения в обмен на переопределение-в-category.html

ответил Ben Baron 8 MarpmThu, 08 Mar 2012 22:23:42 +04002012-03-08T22:23:42+04:0010 2012, 22:23:42
0

Лучшей альтернативой (см. ответ Бнили, почему это предупреждение спасает вас от катастрофы) является использование метода Swizzling. Используя метод swizzling, вы можете заменить существующий метод из категории, не зная, кто "победит", и при этом сохраняя возможность вызова старого метода. Секрет в том, чтобы переопределить другое имя метода, а затем поменять их местами с помощью функций времени выполнения.

#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:));
ответил Sanjit Saluja 25 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowTue, 25 Sep 2012 00:33:19 +0400 2012, 00:33:19
0

Попробуйте это в своем коде:

+(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
ответил Vitaliy Gervazuk 13 PM00000020000000731 2012, 14:57:07
0

Переопределяющие свойства действительны для расширения класса (анонимной категории), но не для обычной категории.

Согласно Apple Docs, использующим расширение класса (анонимная категория), вы можете создать закрытый интерфейс для открытого класса, чтобы закрытый интерфейс мог переопределять открытые для доступа свойства. то есть вы можете изменить свойство с readonly на readwrite.

Вариант использования для этого - когда вы пишете библиотеки, которые ограничивают доступ к общедоступным свойствам, тогда как это же свойство требует полного доступа на чтение и запись в библиотеке.

Ссылка на Документы Apple: https: //developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html

Выполните поиск " Используйте расширения класса, чтобы скрыть личную информацию ".

Таким образом, этот метод действителен для расширения класса, но не для категории.

ответил Kris Subramanian 23 TueEurope/Moscow2014-12-23T23:56:15+03:00Europe/Moscow12bEurope/MoscowTue, 23 Dec 2014 23:56:15 +0300 2014, 23:56:15
0

Категории - это хорошо, но ими можно злоупотреблять. При написании категорий вы должны, как правило, НЕ переосмысливать существующие методы. Это может вызвать странный побочный эффект, так как вы сейчас переписываете код, от которого зависит другой класс. вы можете сломать известный класс и в итоге вывернуть свой отладчик наизнанку. Это просто плохое программирование.

Если вам нужно сделать это, вам действительно следует создать его подкласс.

Тогда предложение мятежа, это большое НЕТ-НЕТ-НЕТ для меня.

Размахивать им во время выполнения - это полное НЕТ-НЕТ-НЕТ.

Вы хотите, чтобы банан выглядел как апельсин, но только во время выполнения? Если вы хотите апельсин, то напишите апельсин.

Не заставляйте банан выглядеть и вести себя как апельсин. И что еще хуже: не превращайте свой банан в секретного агента, который тихо саботирует бананы по всему миру в поддержку апельсинов.

Хлоп!

ответил Leander 6 22012vEurope/Moscow11bEurope/MoscowTue, 06 Nov 2012 13:39:34 +0400 2012, 13:39:34
0

У меня была эта проблема, когда я реализовал метод делегата в категории, а не в главном классе (хотя реализации основного класса не было). Решение для меня было переместить из заголовочного файла основного класса в заголовочный файл категории Это отлично работает

ответил gheese 28 32012vEurope/Moscow11bEurope/MoscowWed, 28 Nov 2012 13:47:04 +0400 2012, 13:47:04

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132