Тип теста NSNotification - PullRequest
       9

Тип теста NSNotification

1 голос
/ 28 сентября 2011

Мне нужно проверить, является ли объект NSNotification.Недостаточно знать, является ли это подклассом, поскольку я хочу различать, является ли это NSNotification или подклассом NSNotification.

Поэтому, чтобы уточнить, мне нужно различать следующее:

  1. NSConcreteNotification
  2. Подкласс NSNotification (но не NSConcreteNotification)

Проблема заключается в том, что NSNotifications на самом деле являются NSConcreteNotifications, а NSConcreteNotification является частным классом, поэтому я не могуиспользуйте его для проверки.

[object isMemberOfClass: [NSNotification class]] // returns NO in both cases
[object isKindOfClass: [NSNotification class]] // returns YES in both cases

Ответы [ 4 ]

2 голосов
/ 28 сентября 2011

Нет никаких оснований для подкласса NSNotification, как вы описываете.Во-первых, NSNotification уже содержит словарь userInfo.Вы можете поместить туда любые данные, которые хотите.Вы можете использовать методы категорий для чтения и записи в этот словарь, если хотите (я делаю это все время).Например, очень распространенная вещь, которую я хочу сделать, это передать некоторый объект, скажем, RNMessage.Поэтому я создаю категорию, которая выглядит следующим образом:

@interface NSNotificationCenter (RNMessage)
- (void)postNotificationName:(NSString *)aName object:(id)anObject message:(RNMessage *)message;
@end

@interface NSNotification (RNMessage)
- (RNMessage *)message;
@end

static NSString * const RNMessageKey = @"message";

@implementation NSNotificationCenter (RNMessage)
- (void)postNotificationName:(NSString *)aName object:(id)anObject message:(RNMessage *)message {
  [self postNotificationName:aName object:anObject userInfo:[NSDictionary dictionaryWithObject:message forKey:RNMessageKey];
}
@end

@implementation NSNotification (RNMessage)
- (RNMessage *)message {
  return [[self userInfo] objectForKey:RNMessageKey];
}

Как отмечает @hypercrypt, вы также можете использовать связанные ссылки для присоединения данных к любому произвольному объекту без создания ивара, но сNSNotification гораздо проще использовать словарь userInfo.Намного легче напечатать уведомление, используя NSLog.Проще их сериализовать.Проще их скопировать.И т. Д. Связанные ссылки - это здорово, но они добавляют много маленьких угловых случаев, которых вам следует избегать, если вам это сойдет с рук.

1 голос
/ 28 сентября 2011

Как уже отмечали другие, полагаться на имя частного класса - плохая идея.Если вы ищете один конкретный подкласс, вы можете просто явно проверить этот класс.

[notification isMemberOfClass:[MyNotificationSubclass class]];

Вы можете использовать несколько операторов для проверки нескольких подклассов, но это будет немного загромождено.Этот метод также требует изменений каждый раз, когда вы добавляете новый класс для поиска.Может быть лучше определить свойство только для чтения, которое указывает, поддерживает ли уведомление функцию, которую вы ищете, так что вы полагаетесь не столько на класс, сколько на его возможности.Вы можете использовать категорию в NSNotification, которая просто возвращает NO для этого свойства, и любые подклассы, имеющие функцию, будут переопределять метод для возврата YES.

@interface NSNotification (MyFeature)
@property (readonly) BOOL hasMyFeature;
@end

@implementation NSNotification (MyFeature)
- (BOOL)hasMyFeature {
    return NO;
}
@end

В подклассах, которые его поддерживают:

- (BOOL)hasMyFeature {
    return YES;
}
- (void)performMyFeature {
    ...
}

Это также позволит вам изменить возможность включения функции уведомления, изменив флаг, возвращаемый для hasMyFeature, и ваш проверочный код будет просто:

if(notification.hasMyFeature) [notification performMyFeature];
1 голос
/ 28 сентября 2011

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

Создание зависимостей от приватного API (включая имена приватных классов) сделает ваш код более хрупким и намного более вероятным в будущем выпуске. Очевидно, что одна из причин, по которой эти классы являются частными, состоит в том, чтобы облегчить инженерам Apple их изменение по своему усмотрению. Например, конкретные подклассы, используемые NSArray и NSMutableArray, только что изменились в недавнем выпуске SDK.

1 голос
/ 28 сентября 2011

Для проверки идентификатора объекта используется NSNotification:

[object isMemberOfClass:[NSNotification class]];`

Чтобы проверить, является ли это NSConcreteNotifications, используйте

[object isMemberOfClass:NSClassFromString(@"NSConcreteNotifications")];

При необходимости измените строку на имя другого класса ...

Затем можно объединить две проверки для «Подкласса NSNotification (но не NSConcreteNotification».

Или:

if ([object isMemberOfClass:NSClassFromString(@"NSConcreteNotifications")])
{
    // It's a NSConcreteNotifications...
}
else if ([object isKindOfClass:[NSNotification class]])
{
    // It's an NSNotification (or subclass) but not an NSConcreteNotifications
}

Или

if ([object isKindOfClass:[NSNotification class]] && ![object isMemberOfClass:NSClassFromString(@"NSConcreteNotifications")])
{ /* ... */ }

Если вы хотите добавить свойства к NSNotification s, вам следует обратиться к Ассоциативные ссылки .

Основная идея:

static const char objectKey;
- (id)object
{
    return objc_getAssociatedObject(self, &objectKey);
}

- (void)setObject:(id)object
{
    objc_setAssociatedObject(self, &objectKey, object, OBJC_ASSOCIATION_RETAIN);
}
...