делегат для одноэлементного объекта - PullRequest
14 голосов
/ 28 февраля 2012

У меня есть NSObject, который является синглтоном. Есть ли проблема с делегатом для этого синглтон-класса? Я обеспокоен тем, что это не удастся для одноэлементного типа.

Вот мой сценарий. У меня есть функция (внутри этого одноэлементного класса), которая выполняет асинхронный запрос на извлечение NSDictionary из API. В основном, когда этот запрос выполнен, я хочу уведомить класс о том, что запрос завершен.

Ответы [ 3 ]

31 голосов
/ 28 февраля 2012

Нет, делегат не потерпит неудачу, но рассмотрите возможность использования NSNotificationCenter вместо:

static NSString *const kMyClassNotificationName = @"myClassNotificationName";

// where you would call a delegate method (e.g. [self.delegate doSomething])
[[NSNotificationCenter defaultCenter] postNotificationName:kMyClassNotificationName object:self userInfo: /* dictionary containing variables to pass to the delegate */];

// where you would set up a delegate (e.g. [Singleton instance].delegate = self)
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doSomething) name:kMyClassNotificationName object:[Singleton instance]];
19 голосов
/ 28 февраля 2012

У вас есть три основных варианта:

  • Использовать делегата.Singelton - это объект, поэтому он может иметь делегата.Если несколько объектов хотят использовать его и должны установить себя в качестве делегатов, вы можете каждый раз сбрасывать их, но это может стать проблематичным.

  • Использовать уведомления, как показано Ричардом Дж. РоссомIII., Но серьезно: мне кажется странным, если у вас есть синглтон, который должен сообщить одному делегату, но вы будете использовать технологию вещания.

  • использовать завершениеблоки, где вызывающие объекты передают блок синглтону, который исполняется, когда синглтон выполнил задачу.См. [NSURLConnection sendAsynchronousRequest:queue:completionHandler:] (хорошо, это не одноэлементный, а метод класса. Принцип тот же), который использует один блок завершения, или большой AFNetworking , который используетблок успеха и неудачи.
    Из примеров кода:

    [[AFGowallaAPIClient sharedClient] getPath:urlString 
                                    parameters:mutableParameters 
                                       success:^(__unused AFHTTPRequestOperation 
                                                 *operation, 
                                                 id JSON) 
        {
            NSMutableArray *mutableRecords = [NSMutableArray array];
            for (NSDictionary *attributes in [JSON valueForKeyPath:@"spots"]) {
                Spot *spot = [[[Spot alloc] initWithAttributes:attributes] autorelease];
                [mutableRecords addObject:spot];
            }
    
            if (block) {
                block([NSArray arrayWithArray:mutableRecords]);
            }
        } failure:^(__unused AFHTTPRequestOperation *operation, NSError *error) {
            if (block) {
                block([NSArray array]);
            }
    }];
    
7 голосов
/ 01 октября 2014

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

  • Если объект A вызывает setDelegate:, после чего сразу же объект B вызывает setDelegate: тогда объект A никогда не получит вызовов делегатов.

  • Вы должны проверить, являетесь ли вы делегатом, прежде чем отключать делегата синглтона.Обычно в dealloc вы звоните singleton.delegate = nil;.Если какой-то другой объект стал делегатом после того, как вы это сделали, то вы просто вызвали неожиданное прекращение его делегирования.

Синглеты с делегатами не являются общепринятым шаблоном.Ваши решения должны различаться в зависимости от того, насколько надежен ваш вариант использования.Вот некоторые решения (в порядке самых простых -> самых надежных).

Упрощайте

Создайте свое приложение так, чтобы в нем никогда не было нескольких объектов, являющихся делегатом-одиночкой нав то же время (это может быть невозможно).

NSNotification

Используйте NSNotificationCenter для сигнализации о событиях вместо делегирования.См. Некоторые другие ответы, опубликованные в этой теме.

Несколько делегатов

Расширьте свой синглтон для поддержки нескольких делегатов.Замените setDelegate: на: addDelegate: и removeDelegate:

@property (atomic) NSMutableArray *delegates;

- (void)addDelegate:(NSObject * <YourProtocol>)foo {
    [self.delegates addObject:foo];
}
- (void)removeDelegate:(NSObject * <YourProtocol>)foo {
    [self.delegates removeObject:foo];
}
- (void)signalDelegateEvent {
    [self.delegates enumerateObjectsUsingBlock:^(id<YourProtocol> obj,
                                                 NSUInteger idx,
                                                 BOOL *stop) {
        // call delegate method `foo` on each delegate
        if ( [obj respondsToSelector:@selector(foo)]) {
            [obj foo];
        } 
    }];
}

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

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