Итак, задача.

Есть клиентское приложение, которое имеет постоянное сокетное соединение. Сервер, периодически, посылает клиентскому приложению набор команд в виде XML. Именем команды является имя ноды в XML. Задача клиентского приложения, обработать эти команды.

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

Мы поступим подругому. Мы сделаем коллекцию, имеющую тип ЗНАЧЕНИЕ-КЛЮЧ, в которой будем хранить селекторы, а в качестве ключа будет имя команды.

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

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

Например, у нас есть команда, точнее ответ сервера на команду login. В данном случае мы сделаем метод-обработчик: -(void) processLoginResponse:(Command *)command;

Этот метод обработает пришедший ответ от сервера и выполнит все необходимые проверки и действия. Что внутри этого метода будет дальше, писать не буду. Задача сделать так, чтобы обработчик сетевых пакетов, вытащил ссылку на метод-обработчик команды login и исполнил его, передав параметром команду.

Итак, в главном классе приложения, который и будет заниматься всем этим, назовем его Engine, создадим метод инициализации коллекции методов:

- (void)initCommandsHolder
{
commandsHolder = [[NSMutableDictionary alloc] init];
//commandsHolder - член класса Engine, собственно и будет той коллекцией
//Создаем селектор для нашего метода-обработчика
SEL theSelector = @selector(processLoginResponse:);
//Описываем сигнатуру для нашего метода
NSMethodSignature * aSignature = [Engine instanceMethodSignatureForSelector:theSelector];
//Создаем инстанцию, которая будет стартовать метод и храниться в коллекции
NSInvocation * anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
//Задаем этой инстанции полученный нами селектор
[anInvocation setSelector:theSelector];
//Сохраняем инстанцию в коллекции
[commandsHolder setObject:anInvocation forKey:@"login"];
}

Итак, у нас есть коллекция, со ссылкой на один метод-обработчик. Далее перейдем к методу, который обрабатывает пакеты от сервера:

- (void) processResponse:(NSString *)response
{
//Десериализуем пакет в инстанс класса Command для дальнейшего использования
Command * command = [[Command alloc]initWithXML:response];
//Проверяем, есть ли в коллекции обработчики
if([commandsHolder count] > 0)
{
//Получаем инстанцию стартера для метода-обработчика по имени команды
NSInvocation * anInvocation = [commandsHolder objectForKey:[command name]];
//Проверяем, удалось ли получить инстанцию
if(anInvocation)
{
//Устанавливаем инстанции целевой класс, у которого есть этот метод-обработчик
[anInvocation setTarget:self];
//Задаем аргумент для запуска
//Индекс равен 2, потому как индексы 0 и 1 являются зарезервированными и скрытыми
//Индекс 0 содержит ссылку на инстанцию стартера, а индекс 1 ссылку на сигнатуру метода
[anInvocation setArgument:&command atIndex:2];
//Запускаем метод-обработчик
[anInvocation invoke];
}
}
}

Все готово. Пока у нас в коллекции один метод, но мы с легкостью можем добавить множество методов и избавить себя от кучи IF ELSE, которые мозолят глаза.