1

オブジェクトが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

4 に答える 4

2

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 が指摘しているように、関連付けられた参照を使用して、ivar を作成せずに任意のオブジェクトにデータを添付することもできますがNSNotification、userInfo ディクショナリを使用する方がはるかに簡単です。を使用して通知を印刷する方がはるかに簡単NSLogです。それらをシリアル化する方が簡単です。それらをコピーする方が簡単です。関連参照は素晴らしいものですが、回避できる場合は避けるべき多くの小さなコーナー ケースが追加されます。

于 2011-09-28T13:45:40.717 に答える
1

idオブジェクトをテストするには、次のようにNSNotification使用します。

[object isMemberOfClass:[NSNotification class]];`

それがNSConcreteNotifications使用であるかどうかをテストするには

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

必要に応じて、文字列を別のクラスの名前に変更します。

次に、「NSNotificationのサブクラス(ただしNSConcreteNotificationではない)」の2つのチェックを組み合わせることができます。

また:

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を調べる必要があります。

基本的な考え方は次のとおりです。

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

- (void)setObject:(id)object
{
    objc_setAssociatedObject(self, &objectKey, object, OBJC_ASSOCIATION_RETAIN);
}
于 2011-09-28T12:54:51.533 に答える
1

他の人が指摘しているように、プライベート クラスの名前に頼るのは悪い考えです。1 つの特定のサブクラスを探している場合は、そのクラスを明示的に確認できます。

[notification isMemberOfClass:[MyNotificationSubclass class]];

複数のステートメントを使用して複数のサブクラスをチェックすることもできますが、それは少し雑然とします。このメソッドも、検索する新しいクラスを追加するたびに変更する必要があります。通知が探している機能をサポートしているかどうかを示す読み取り専用プロパティを定義する方がよい場合があります。これにより、クラスの能力ほどクラスに依存しなくなります。このプロパティを単に返す NSNotification のカテゴリを使用できますNO。この機能を持つサブクラスはメソッドをオーバーライドして return し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];
于 2011-09-28T14:17:15.693 に答える
1

それは本当に悪い考えのように聞こえます。通知を最初に受け取った時点で、通知のコールバック メソッドに明示的な引数として渡されるため、通知の型が既にわかっています。通知を別のオブジェクトの厳密に型指定されたプロパティとして保存するか、コレクションに追加する場合は適切なキーの下の辞書に挿入するか、型情報を保持しない他のメソッドに渡して簡単にすることを検討してください。後で特定します。

プライベート API (プライベート クラスの名前を含む) への依存関係を作成すると、コードが脆弱になり、将来のリリースで壊れる可能性が高くなります。明らかに、これらのクラスが非公開である理由の 1 つは、Apple のエンジニアが必要に応じてクラスを簡単に変更できるようにするためです。たとえば、NSArray と NSMutableArray で使用される具体的なサブクラスは、SDK の最近のリリースで変更されました。

于 2011-09-28T13:08:35.740 に答える