Я хотел бы указать протокол Objective-C с дополнительной процедурой. Когда процедура не реализуется классом, соответствующим протоколу, я бы хотел использовать реализацию по умолчанию на своем месте. Есть ли место в самом протоколе, где я могу определить эту реализацию по умолчанию? Если нет, то какова наилучшая практика сокращения копирования и вставки этой реализации по умолчанию повсюду?Как обеспечить реализацию по умолчанию для протокола Objective-C?
ответ
Протоколы Objective-C не имеют возможности для реализации по умолчанию. Они представляют собой чисто коллекции деклараций методов, которые могут быть реализованы другими классами. Стандартная практика Objective-C заключается в проверке объекта во время выполнения, чтобы увидеть, отвечает ли он данному селектору перед вызовом этого метода на нем, используя - [NSObject отвечаетSoSelector:]. Если e-объект не отвечает на данный селектор, метод не вызывается.
Одним из способов достижения результата, который вы ищете, является определение метода, который инкапсулирует поведение по умолчанию, которое вы ищете в вызывающем классе, и вызывать этот метод, если объект не проходит тест.
Другим подходом было бы сделать этот метод обязательным в протоколе и предоставить стандартные реализации в суперклассах любых классов, в которых вы, возможно, не захотите предоставить конкретную реализацию.
Возможно, есть и другие варианты, но, вообще говоря, в Objective-C нет конкретной стандартной практики, за исключением, возможно, просто не вызывать данный метод, если он не был реализован объектом, за мой первый абзац, выше.
По-настоящему увлекательным способом является использование среды выполнения. При пуске, в самом начале выполнения программы, выполните следующие действия:
- Перечислять все классы, найти классы, которые реализуют протокол
- Проверьте, если класс реализует метод
- Если нет, добавить к классу значение по умолчанию
Этого можно достичь без особых проблем.
Как вы смеете называть это хакерским ;) – 2010-12-02 01:50:03
Я действительно написал полный модуль общественного домена, чтобы сделать именно это. Это не так хакально, как кажется, так как использует полностью поддерживаемые и документированные функциональные возможности и тщательно протестировано в производственном коде. http://code.google.com/p/libextobjc/source/browse/extobjc/Modules/EXTConcreteProtocol.h – 2010-12-02 01:50:16
OK Я заменяю «хакерский» на «увлекательный». Это удовлетворит всех вас? – Yuji 2010-12-02 02:18:38
Нет стандартного способа для этого, поскольку протоколы не должны определять какие-либо реализации.
Поскольку Objective-C поставляется с аккуратным временем выполнения, вы можете, конечно, добавить такое поведение, если действительно думаете, что вам нужно сделать это таким образом (и нет возможности, достигнув того же с наследованием).
Допустим, вы объявили MyProtocol, а затем просто добавить интерфейс с таким же именем в файле .h под декларацией протокола:
@interface MyProtocol : NSObject <MyProtocol>
+ (void)addDefaultImplementationForClass:(Class)conformingClass;
@end
и создать соответствующий файл реализации (с использованием MAObjCRuntime для удобства чтения здесь, но стандартные функции во время выполнения не было бы гораздо больше кода):
@implementation MyProtocol
+ (void)addDefaultImplementationForClass:(Class)conformingClass {
RTProtocol *protocol = [RTProtocol protocolWithName:@"MyProtocol"];
// get all optional instance methods
NSArray *optionalMethods = [protocol methodsRequired:NO instance:YES];
for (RTMethod *method in optionalMethods) {
if (![conformingClass rt_methodForSelector:[method selector]]) {
RTMethod *myMethod = [self rt_methodForSelector:[method selector]];
// add the default implementation from this class
[conformingClass rt_addMethod:myMethod];
}
}
}
- (void)someOptionalProtocolMethod {
// default implementation
// will be added to any class that calls addDefault...: on itself
}
Тогда вам просто нужно позвонить
[MyProtocol addDefaultImplementationForClass:[self class]];
в инициализаторе вашего класса, соответствующего протоколу, и все стандартные методы будут добавлены.
Поскольку Райан упоминает, что для протоколов нет реализации по умолчанию, другой вариант реализации в суперклассе - это реализовать класс класса «Handler», который может содержаться в любом классе, который хочет предоставить реализацию по умолчанию, соответствующий метод затем вызывает реализацию обработчиков по умолчанию.
В результате я создал макрос, который имеет реализацию метода по умолчанию.
Я определил его в заголовочном файле протокола, а затем это всего лишь один лайнер в каждой реализации.
Таким образом, мне не нужно менять реализацию несколькими местами, и это делается во время компиляции, поэтому магия времени выполнения не требуется.
Я согласен с "w.m." Очень приятным решением является включение всех реализаций по умолчанию в интерфейс (с тем же именем, что и протокол). В методе «+ initialize» любого подкласса он может просто скопировать любые нереализованные методы из интерфейса по умолчанию в себя.
Следующие вспомогательные функции работали для меня
#import <objc/runtime.h>
// Get the type string of a method, such as "[email protected]:".
// Caller must allocate sufficent space. Result is null terminated.
void getMethodTypes(Method method, char*result, int maxResultLen)
{
method_getReturnType(method, result, maxResultLen - 1);
int na = method_getNumberOfArguments(method);
for (int i = 0; i < na; ++i)
{
unsigned long x = strlen(result);
method_getArgumentType(method, i, result + x, maxResultLen - 1 - x);
}
}
// This copies all the instance methods from one class to another
// that are not already defined in the destination class.
void copyMissingMethods(Class fromClass, Class toClass)
{
// This gets the INSTANCE methods only
unsigned int numMethods;
Method* methodList = class_copyMethodList(fromClass, &numMethods);
for (int i = 0; i < numMethods; ++i)
{
Method method = methodList[i];
SEL selector = method_getName(method);
char methodTypes[50];
getMethodTypes(method, methodTypes, sizeof methodTypes);
if (![toClass respondsToSelector:selector])
{
IMP methodImplementation = class_getMethodImplementation(fromClass, selector);
class_addMethod(toClass, selector, methodImplementation, methodTypes);
}
}
free(methodList);
}
Тогда вы называете его в инициализаторе класса, такие как ...
@interface Foobar : NSObject<MyProtocol>
@end
@implementation Foobar
+(void)initialize
{
// Copy methods from the default
copyMissingMethods([MyProtocol class], self);
}
@end
Xcode будет предупреждать о FOOBAR отсутствующих методов, но вы может игнорировать их.
Этот метод копирует только методы, а не ивары. Если методы обращаются к членам данных, которые не существуют, вы можете получить странные ошибки. Вы должны убедиться, что данные совместимы с кодом. Это как если бы вы сделали reinterpret_cast от Foobar до MyProtocol.
- 1. Как вы можете обеспечить реализацию по умолчанию для UIPageViewControllerDataSource?
- 2. По умолчанию реализация протокола протокола
- 3. Вызов протокола по умолчанию по стандартным методам
- 4. По умолчанию реализации протокола для Enum
- 5. Как обеспечить реализацию по умолчанию для метода OnValidate для LINQ to SQL?
- 6. Как обеспечить реализацию ProjectItem.get_FileNames (i)?
- 7. Как обеспечить реализацию в C++?
- 8. Обеспечить реализацию тестирования стеки монады
- 9. Определить реализацию по умолчанию для инъекций весной?
- 10. обеспечить реализацию интерфейса
- 11. ObjectiveC UISwitch установлен по умолчанию на OFF
- 12. Добавить реализацию по умолчанию свойств
- 13. Как определить реализацию по умолчанию в HK2?
- 14. Можно ли переопределить метод по умолчанию по умолчанию протокола?
- 15. установка протокола обратно по умолчанию
- 16. Реализация метода равных по умолчанию для протокола
- 17. Swift: предоставление реализации протокола по умолчанию в расширении протокола
- 18. Есть ли способ сделать реализацию по умолчанию для протокола в Swift?
- 19. Как вы используете реализацию протокола по умолчанию с помощью функции performSelector в swift?
- 20. Map.getOrElse Scala - как обеспечить функцию по умолчанию
- 21. Как переопределить реализацию определенного метода протокола
- 22. Как установить реализацию по умолчанию для нескольких профилей весной?
- 23. Возможно ли наследовать реализацию IShellFolder по умолчанию?
- 24. Обеспечить конкретный тип для реализации Generic протокола
- 25. , что означает реализацию по умолчанию интерфейса
- 26. Как сделать программу «обработчиком» по умолчанию для определенного протокола?
- 27. Получение «Контекст не является конструктивным. Добавить конструктор по умолчанию или обеспечить реализацию IDbContextFactory.»
- 28. Синтаксис ObjectiveC для указания имени протокола в аргументе метода
- 29. Как я могу обеспечить тестовую реализацию для «предоставленной» зависимости
- 30. Класс не соответствует протоколу с расширением, содержащим реализацию по умолчанию
Этот пост предлагает элегантное, новое решение: используйте категорию в NSObject. http://stackoverflow.com/questions/19329309/whats-wrong-with-using-a-category-on-nsobject-to-provide-a-default-protocol-imp?rq=1 – 2014-04-17 13:25:35