Я создал библиотеку, которая может загружать данные JSON, которые затем помещаются в NSDictionary. Я обертываю этот класс простым движком Twitter, который позволяет мне перетягивать шкалу времени моих друзей, публиковать обновления и публиковать обновления с моим местоположением GPS. Из моего ограниченного опыта работы с Objective-C способ связать все - с делегированием. Я установил свойство делегата, которое вызывает асинхронный результат для селектора или сигнатуры метода. Я даже могу создать дополнительный или обязательный интерфейс для делегата, который позволит Xcode немного помочь мне с реализацией делегата. Чтобы узнать об использовании делегатов в Objective-C, я создал этот простой проект.
http://www.smallsharptools.com/downloads/ObjC/Delegates.zip
Он определяет класс Worker, который позволяет вам инициализировать класс делегатом. Когда работа завершена с помощью метода doWork, он ищет сигнатуру метода в делегате, чтобы отправить ему сообщение обратно. Используется следующий код.
if([[self delegate] respondsToSelector:@selector(workFinished:)]) {
NSString *msg = @"That's it? Easy!";
[[self delegate] workFinished:msg];
}
Ищет workFinished: метод для возврата сообщения. Я объявил подпись этого метода как необязательный интерфейс со следующим кодом в заголовке Worker.h.
@protocol WorkerNotifications
@optional
- (void) workFinished: (NSString *) msg;
@end
Вы можете увидеть остальную часть проекта из загрузки для всех деталей. Но эти 2 фрагмента кода показывают, как работает этот шаблон делегирования. Но с классом Twitter мне нужно знать контекст метода, который запустил асинхронное действие, которое приводит к обратному вызову метода делегата. Если я вызываю метод sendUpdate более одного раза из вызывающего класса, как мне узнать контекст обратного вызова?
Обычно с таким языком, как JavaScript, Java или C #, я бы создал встроенное замыкание или анонимный класс, который имел бы доступ к начальному контексту, но в настоящее время это невозможно с Objective-C на iPhone. Я обнаружил, что этот вопрос уже задавался и отвечал на StackOverflow.
Реализация анонимного делегата в Objective-C?
Итак, я пропустил необязательный интерфейс и вместо этого передал в селектор, который вызовет класс Twitter, когда асинхронное действие будет завершено. Вызов для запуска этого действия выглядит как ...
CMTwitterEngine *engine = [[CMTwitterEngine alloc] initWithDelegate:self];
[engine setSendUpdateFinished:@selector(sendUpdateFinished:)];
[engine setSendUpdateFailed:@selector(sendUpdateFailed:)];
[engine setParsingSendUpdateFailed:@selector(parsingSendUpdateFailed:)];
[engine setUsername:TWITTER_USERNAME pass:TWITTER_PASSWORD];
[engine sendUpdate:statusUpdateText.text];
Этот код сначала инициализирует ссылку на двигатель с помощью self в качестве делегата. Чтобы прикрепить обратные вызовы, я отправляю селекторы, которые у меня изначально были в сигнатуре метода sendUpdate, но вызовы методов стали довольно длинными. Я решил просто установить свойства селекторов. Это все работает, но я не уверен, что мне нравится, как это работает, поскольку это только частично решает мою проблему.
Чтобы завершить этот пример, я заканчиваю асинхронную работу и, в конце концов, вызываю внутренний метод, который ищет данный селектор и вызывает его, если он определен.
- (void)sendUpdateFinished:(NSDictionary *)dictionary {
if (self.sendUpdateFinished != nil) {
[self.delegate performSelector:self.sendUpdateFinished withObject:dictionary];
}
}
Я могу передать сообщение о состоянии, чтобы отправить его как обновление Twitter, но у меня все еще нет контекста исходящего вызова. Что если я хочу вызвать sendUpdate более одного раза и первый асинхронный вызов все еще выполняется? А что, если второй вызов заканчивается первым? Они оба будут иметь себя в качестве делегата, поэтому мне придется либо как-то отслеживать контекст, либо передавать их другому селектору, чтобы различать их, что также не удовлетворяет мои потребности. Что произойдет, если у меня будет 3, 4 или 5 асинхронных вызовов? Мне нужно знать, какие из них были успешно отправлены и когда они завершены.
Похоже, единственный способ, которым я могу сделать все это, это создать класс, который содержит все свойства, необходимые для контекста, сделать так, чтобы этот класс выступал в качестве делегата для вызова асинхронного метода Twitter, а затем отчитывался в родительский класс, который, вероятно, UIViewController. Я бы выбрал этот подход, но я еще не читал об этом подходе и не видел ни одного примера кода, который делает это.
Что бы вы сделали? Как бы вы обрабатывали несколько выходящих асинхронных вызовов, которые могли бы заканчиваться в другом порядке, чем выход, и затем обрабатывали бы их с контекстом после завершения?