Как реализовать или изменить таблицу диспетчеризации методов в Objective-C? - PullRequest
3 голосов
/ 15 июня 2009

Иногда полезно настроить таблицу диспетчеризации методов, чтобы вызывающий метод A вызывал метод AImpl (), а вызывающий метод A в другое время вызывает BImpl (). Как это можно сделать в Objective-C для метода, который автоматически вызывается системой (например, методы делегата)?

Например, если система впервые вызывает viewDidAppear, я хочу, чтобы она вызывала viewAppearFirstTime, тогда как впоследствии вызов viewDidAppear попадет в совершенно другое тело метода (вместо выполнения проверки if-else внутри кода с использованием логического флага). 1003 *

Другой пример, скажем, URiew drawRect очень часто вызывается в приложении, если drawRect, вызываемый в первый раз, отличается от последующих, я не хочу включать if-тест, потому что этот код труднее читать и проверка также не нужна после первого раза.

Ответы [ 4 ]

3 голосов
/ 15 июня 2009

Я здесь предостерегаю: конкретный случай, который вы описываете, вероятно, не следует делать таким образом. Он почти наверняка слишком умный и, вероятно, его следует разделить на viewDidLoad и viewWillAppear, а не на две версии viewWillAppear. Тем не менее, проблема действительно возникает.

Мое предпочтительное решение - сохранить SEL, который указывает на то, что я хочу сделать. Например, я использую эту технику для «следующего действия» после сложной асинхронной операции:

if (self.nextActionSelector != NULL)
{
    [self performSelector:self.nextActionSelector];
}

Таким образом, для этого вы можете использовать viewWillAppearSelector, который будет изменяться с течением времени, а viewWillAppear будет просто вызывать все, на что он указывает.

Рекомендация Бена о методе Swizzling полезна в некоторых случаях, но чаще, когда вы пытаетесь изменить поведение какого-либо существующего объекта, а не себя. Это может действительно сделать отладку веселой .... Хорошо, на самом деле не весело. Болезненные. Очень больно.

Помимо этого, я бы посмотрел на -forwardInvocation:, который можно использовать для ответа на сообщения, которые вы непосредственно не реализуете. Затем вы можете переписать вызов, чтобы вызвать метод, который вам действительно нужен. Однако это не совсем то, что должно быть использовано. Это для прозрачной переадресации вызовов на другие объекты. Но, по крайней мере, отладка не так сложна, поскольку отладчик пойдет туда, куда вы ожидаете.

Обычно в этом случае, а не логическое значение, я ищу доказательства того, что я уже работал. Проверка, установлена ​​ли уже view, или какое-либо другое значение, которое инициализируется в первый раз, поэтому мне не нужна специальная переменная, и поэтому я устойчив к вещам, которые очищают мое состояние (например, практика iPhone по сбросу вещей, когда память в обтяжку). Там, где это возможно, я делаю эти вещи самоинициализирующимися в их получателях, вместо того, чтобы какая-то внешняя сторона имела специальную логику для первого раза. Простая логика делает обслуживание намного проще, и, эй, NSInvocation сумасшедший медленный (хорошо, вы не заметите этого, кроме как в узком цикле, но это примерно в 500 раз медленнее, чем вызов метода в моих тестах. сказал, что я не предлагаю принимать это решение по производительности, просто ремонтопригодность).

2 голосов
/ 15 июня 2009

Среда выполнения Objective C позволяет вам изменять отображение от селектора к реализации метода во время выполнения, и это довольно гладко. Проверьте эту статью на CocoaDev для получения дополнительной информации: CocoaDev: Метод Swizzling . Вы можете использовать любую функцию, для которой у вас есть существующее сопоставление, поэтому вы можете эффективно заменить любую функцию, которую вы хотите во время выполнения obj-c.

Хотя на самом деле это не то, что вы должны делать везде - сначала я попробую NSInvocations. Поскольку вы можете написать свою собственную функцию viewDidAppear и вызывать вашу viewAppearFirstTime: функцию из этого, метод swizzling, вероятно, излишний.

Удачи!

2 голосов
/ 15 июня 2009

Если вы хотите изменить метод для всех экземпляров класса, вы можете сделать это с помощью метода swizzling. Я никогда не слышал о том, чтобы он использовался для этой цели, но вы можете достичь того, что вы хотите, используя class_replaceMethod изнутри вашего viewDidAppearFirstTime.

Однако, если вы хотите изменить диспетчеризацию метода для одного экземпляра, я думаю, что ваш единственный вариант - это условный оператор в вашем viewDidAppear методе или , чтобы рассмотреть редизайн, который не требует отдельных методов при первом и последующих появлениях (из вашего описания, кажется, имеет смысл разделить ваш код на функции viewDidLoad и viewWillAppear).

2 голосов
/ 15 июня 2009

Прочитайте это , затем поместите ваши NSInvocation экземпляры в NSDictionary.

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