2010-02-03 2 views
4

Я создал библиотеку, которая может загружать данные JSON, которые затем помещаются в NSDictionary. Я обернуваю этот класс простым движком Twitter, который позволяет мне вытащить временные рамки моих друзей, опубликовать обновление и опубликовать обновление с моим местоположением GPS. Из моего ограниченного опыта с Objective-C способ подключения ко всему связан с делегацией. Я устанавливаю свойство делегата, которое возвращает асинхронный результат либо селектору, либо методу. Я даже могу создать необязательный или требуемый интерфейс для делегата, который позволит Xcode немного помочь мне в реализации делегирования. Чтобы узнать об использовании делегатов в Objective-C, я создал этот простой проект.Как мне решить проблему множественных обратных вызовов для одного и того же делегата в 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]; 
} 

Он ищет работуFinished: метод для передачи сообщения. Я объявила эту сигнатуру метода как дополнительный интерфейс со следующим кодом в заголовке Worker.h.

@protocol WorkerNotifications 
    @optional 
    - (void) workFinished: (NSString *) msg; 
    @end 

Вы можете увидеть остальную часть проекта из загрузки для всех деталей. Но эти 2 фрагмента кода показывают, как работает этот шаблон делегирования. Но с классом Twitter мне нужно знать контекст метода, который запустил асинхронное действие, которое приводит к обратному вызову методу делегата. Если я вызову метод sendUpdate более одного раза из вызывающего класса, как я должен знать контекст обратного вызова?

Обычно с языком, как JavaScript, Java или C#, я бы создал встроенное закрытие или анонимный класс, который имел бы доступ к исходному контексту, но в настоящее время это не возможно с Objective-C на iPhone. Я обнаружил, что этот вопрос уже задан и ответил на StackOverflow.

Anonymous delegate implementation in 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. Я бы взял этот подход, но я не читал об этом подходе или не видел какой-либо пример кода, который делает это.

Что вы хотите сделать? Как бы вы справились с многочисленными асинхронными вызовами, которые могли закончиться в другом порядке, чем выходить, а затем обрабатывать их с контекстом после завершения?

ответ

2

Я должен второй (или третий) ранее писал ответы в этой NSNotificationCenter, вероятно, что вы ищете здесь.

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

  1. NSNotifications имеет имя, которое вы определяете, которое является только NSString. Уведомления могут быть опубликованы по имени и объекту для получения уведомлений по имени.

  2. При отправке уведомления может быть предоставлен объект notificationSender и/или словарь пользовательской информации. Уведомление - это прямой способ определить, кто отправил данное уведомление, когда он обрабатывается получателем. UserInfo - это NSDictionary, который может использоваться для предоставления дополнительной информации о контексте вместе с уведомлением.

Таким образом, вместо того, чтобы заставлять всех работников принять к неофициальному протоколу и возни со стилем отражения вызывающей методы, во время выполнения вы просто зарегистрировать экземпляры рабочих с NSNotificationCenter. Обычно регистрация в NSNotificationCenter выполняется в методе init каждого рабочего класса. Экземпляры каждого типа работников затем обычно устанавливаются как «замороженные» объекты в NIB или могут быть запрограммированы в делегате приложения, чтобы они были зарегистрированы в центре уведомлений на ранней стадии жизни приложения.

Когда вещь происходит проводке NSNotification к NSNotificationCenter (который является по существу одиночки), а затем все остальное, что прописал получить этот конкретный тип уведомления будет иметь метод, названный, который был указан для обработки этого типа уведомления. После этого эти методы могут затем вызвать общий метод обратно отправителя (полученный методом объекта NSNotification), чтобы сообщить отправителю, что они завершили свою работу.

После того, как каждый известный работник проверил общий метод отправителя, он может перейти к какому-либо выполнению кода завершения работы.

+0

Итак, любой контекст может быть помещен в userInfo NSDictionary? Похоже, что уведомления могут использоваться более чем в одном экземпляре класса, а также пока они оба настроены таким образом. Этот список ссылок от Apple должен помочь мне начать работу. http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html Спасибо Терри! – Brennan

+0

Пока вы можете сохранить его в качестве значения в словаре, вы можете передавать вещи по мере необходимости. Абсолютно уведомления могут быть отправлены и получены более чем одним классом. В целом они способствуют развязыванию, когда вы хотите, чтобы классы A, B, C и D выполняли некоторые действия, когда происходит какое-то событие, но вы не хотите, чтобы ваш код обработки событий обязательно должен был знать о классах A, B, C , или D. –

+0

Один совет - убедитесь, что вы удалили() своих наблюдателей, объекты, которые вы регистрируете для получения уведомлений, из NSNotificationCenter, когда они больше не нужны. Как правило, если объект зарегистрирован как наблюдатель в методе init, тогда хорошее место для их удаления находится в их реализации dealloc(). –

1

Одна вещь, которую следует учитывать, это использовать уведомления. Упрощает код, делает вещи менее плотными.