Шаблон KVO Dispatcher с методом в качестве контекста - PullRequest
1 голос
/ 31 декабря 2010

Я пытался использовать то, что выглядит как очень умный шаблон KVO , который разрешает селектор для указателя метода, который может быть передан как контекст.

Последняя частьчасть шаблона вызывает у меня некоторые проблемы:

- (void)observeValueForKeyPath:(NSString *)keyPath 
    ofObject:(id)object 
    change:(NSDictionary *)change 
    context:(void *)context
{
    Method m = (Method)context;
    (void(*)(id,SEL,id,id,id))(m->method_imp)(owner, m->method_name, keyPath, object, change);
}

В частности, часть, где указатель метода разыменовывается и, по-видимому, вызывается.

(void(*)(id,SEL,id,id,id))(m->method_imp)(owner, m->method_name, keyPath, object, change);

Я получаю эту ошибку компиляции error: dereferencing pointer to incomplete type

Я очень плохо знаком с Objective-C и C и у меня есть два вопроса:

  1. Как называется приведенный выше синтаксис?Я хотел бы прочитать об этом больше.
  2. Как мне исправить эту линию для работы?

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

1 Ответ

2 голосов
/ 31 декабря 2010

Это может быть так же просто, как импортировать заголовки времени выполнения Objective C:

#import <objc/runtime.h>

Тогда компилятор знает, что такое Method, и вы сможете успешно разыменовать его.


(void(*)(id,SEL,id,id,id))(m->method_imp)

делает m->method_imp указателем на (пустую) функцию с аргументами типа id,SEL,id,id,id.Каждый метод Objective-C на самом деле является функцией C, причем первый аргумент является указателем на объект (доступ к которому можно получить с помощью self), а второй - на селектор (доступный с помощью _cmd) после обычногопараметры метода.

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

Чтобы узнать больше об этом, пожалуйста, найдите указатели на функции и узнайте, как работает среда выполнения Objective-C.


По сути, вы могли бы также использовать следующий код:

objc_msgSend(owner, m->method_name, keyPath, object, change);

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

objc_msgSend(owner, (SEL)context, keyPath, object, change);

Что-то о IMP тогда, которое m->method_imp определяется как:

В <objc/objc.h>, IMP был определен следующим образом:

typedef id          (*IMP)(id, SEL, ...); 

Немного странный синтаксис, поскольку на самом деле не ясно, какой тип является, а какой -Определение.Ну, только IMP - это определение в данном случае, остальные id (*)(id, SEL, ...) - это тип.Чтобы узнать больше об этом, найдите статью об указателях функций.

Итак, это указатель на функцию, которая возвращает объект (id) и принимает несколько аргументов: значения по умолчанию Objective-C ивероятно, еще немного (обозначается ..., что означает, что может быть дополнительными аргументами)

...