Я думаю, что всем не хватает настоящей проблемы. Дело не в методах доступа, а скорее в том, что NSOrderedSet
не является подклассом в NSSet
. Таким образом, когда -interSectsSet:
вызывается с упорядоченным набором в качестве аргумента, это не получается.
NSOrderedSet* setA = [NSOrderedSet orderedSetWithObjects:@"A",@"B",@"C",nil];
NSSet* setB = [NSSet setWithObjects:@"C",@"D", nil];
[setB intersectsSet:setA];
не удается с *** -[NSSet intersectsSet:]: set argument is not an NSSet
Похоже, исправление состоит в том, чтобы изменить реализацию операторов множеств, чтобы они прозрачно обрабатывали типы. Нет причин, по которым -intersectsSet:
должен работать с упорядоченным или неупорядоченным множеством.
Исключение происходит в уведомлении об изменении. Предположительно в коде, который обрабатывает обратные отношения. Так как это происходит только тогда, когда я устанавливаю обратную связь.
Следующее помогло мне
@implementation MF_NSOrderedSetFixes
+ (void) fixSetMethods
{
NSArray* classes = [NSArray arrayWithObjects:@"NSSet", @"NSMutableSet", @"NSOrderedSet", @"NSMutableOrderedSet",nil];
[classes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSString* name = obj;
Class aClass = objc_lookUpClass([name UTF8String]);
[MF_NSOrderedSetFixes fixMethodWithSetArgument:@selector(intersectsSet:) forClass:aClass];
[MF_NSOrderedSetFixes fixMethodWithSetArgument:@selector(isSubsetOfSet:) forClass:aClass];
}];
}
typedef BOOL (*BoolNSetIMP)(id _s,SEL sel, NSSet*);
/*
Works for all methods of type - (BOOL) method:(NSSet*) aSet
*/
+ (void) fixMethodWithSetArgument:(SEL) aSel forClass:(Class) aClass
{
/* Check that class actually implements method first */
/* can't use get_classInstanceMethod() since it checks superclass */
unsigned int count,i;
Method method = NULL;
Method* methods = class_copyMethodList(aClass, &count);
if(methods) {
for(i=0;i<count;i++) {
if(method_getName(methods[i])==aSel) {
method = methods[i];
}
}
free(methods);
}
if(!method) {
return;
}
// Get old implementation
BoolNSetIMP originalImp = (BoolNSetIMP) method_getImplementation(method);
IMP newImp = imp_implementationWithBlock(^BOOL(NSSet *_s, NSSet *otherSet) {
if([otherSet isKindOfClass:[NSOrderedSet class]]) {
otherSet = [(NSOrderedSet*)otherSet set];
}
// Call original implementation
return originalImp(_s,aSel,otherSet);
});
method_setImplementation(method, newImp);
}
@end
Если вы хотите, чтобы это было достаточно универсальным, чтобы обрабатывать любое количество аргументов, попробуйте использовать неуниверсальный делегат Action:
protected void udpCommand(Action command)
{
while(!linkDownFail)
{
try
{
command();
break;
}
catch
{
LinkStateCallBack(ip, getLinkStatus());
if (linkDownFail) throw new LinkDownException();
Thread.Sleep(100);
}
}
return;
}
В C # 3.0 вы можете вызвать его следующим образом:
udpCommand(() => noParameterMethod());
udpCommand(() => singleParameterMethod(value));
udpCommand(() => manyParameterMethod(value, value2, value3, value4));
В C # 2.0 это немного уродливее:
udpCommand(delegate { noParameterMethod(); });
udpCommand(delegate { singleParameterMethod(value); });
udpCommand(delegate { manyParameterMethod(value, value2, value3, value4); });
Это дает вам отложенное выполнение, не привязывая вас к определенной сигнатуре метода.
EDIT
Я просто заметил, что я как бы украл комментарий Марка Гравелла ... извинения, Марк. Чтобы ответить на вопрос, как можно уменьшить дублирование, вы можете заставить метод Action
вызывать метод Func
, например:
protected void udpCommand(Action command)
{
udpCommand(() => { command(); return 0; });
}
Я считаю (и могу ошибаться), что возвращение 0 не более затратно, чем (неявно) возвращение void, но, возможно, я здесь далеко. Даже если у этого есть своя стоимость, он поместит в стек лишь крошечную мелочь. В большинстве случаев дополнительные расходы не причинят вам никакого вреда.
Вы имеете в виду:
protected void udpCommand<T>(Action<T> command, T value) {...}
С вызовом:
udpCommand(someUdpCommand, arg);
Обратите внимание, что это может работать лучше на C # 3.0, который имеет более сильный вывод универсального типа, чем C # 2.0.
Я думаю, вам просто нужно вынуть (значение T) после "команды".
Вы пытаетесь сделать это ...
protected void udpCommand<T>(Action<T> command, T value)
{
while(!linkDownFail)
{
try
{
command(value);
// etc.
}
}
}
Тогда это будет работать так ...
public void ActionWithInt( int param )
{
// some command
}
Action<int> fp = ActionWithInt;
udpCommand<int>( fp, 10 ); // or whatever.