10

サブクラス化しようとしていNSNotificationます。

Apple のドキュメントにはNSNotification、次のように記載されています。

NSNotificationインスタンス変数のないクラス クラスタです。そのため、プリミティブ メソッド、、および をサブクラス化NSNotificationし、オーバーライド する必要があります。任意の指定イニシャライザを選択できますが、イニシャライザが (経由で)の の実装を呼び出さないことを確認してください。 直接インスタンス化することを意図しておらず、その メソッドは例外を発生させます。nameobjectuserInfoNSNotificationinit[super init]NSNotificationinit

しかし、これは私には明らかではありません。このような初期化子を作成する必要がありますか?

-(id)initWithObject:(id)object
{
    return self;
}
4

4 に答える 4

14

サブクラス化NSNotificationは特殊な​​操作です。ここ数年で1、2回しか見たことがないと思います。

通知と一緒に物事を渡したい場合は、それがuserInfoプロパティの目的です。直接アクセスしたくない場合はuserInfo、カテゴリを使用してアクセスを簡素化できます。

@interface NSNotification (EasyAccess)

@property (nonatomic, readonly) NSString *foo;
@property (nonatomic, readonly) NSNumber *bar;

@end

@implementation NSNotification (EasyAccess)

- (NSString *)foo {
  return [[self userInfo] objectForKey:@"foo"];
}

- (NSNumber *)bar {
  return [[self userInfo] objectForKey:@"bar"];
}

@end

このアプローチを使用して、NSNotification作成を簡素化することもできます。たとえば、カテゴリには次のものも含めることができます。

+ (id)myNotificationWithFoo:(NSString *)foo bar:(NSString *)bar object:(id)object {
  NSDictionary *d = [NSDictionary dictionaryWithObjectsForKeys:foo, @"foo", bar, @"bar", nil];
  return [self notificationWithName:@"MyNotification" object:object userInfo:d];
}

何らかの奇妙な理由で、プロパティを変更可能にする必要がある場合は、それを実現するために連想参照を使用する必要があります。

#import <objc/runtime.h>
static const char FooKey;
static const char BarKey;

...

- (NSString *)foo {
  return (NSString *)objc_getAssociatedObject(self, &FooKey);
}

- (void)setFoo:(NSString *)foo {
  objc_setAssociatedObject(self, &FooKey, foo, OBJC_ASSOCIATION_RETAIN);
}

- (NSNumber *)bar {
  return (NSNumber *)objc_getAssociatedObject(self, &BarKey);
}

- (void)setBar:(NSNumber *)bar {
  objc_setAssociatedObject(self, &BarKey, bar, OBJC_ASSOCIATION_RETAIN);
}

...
于 2011-09-28T16:28:10.390 に答える
2

これはうまくいくようです。例えば:

#import "TestNotification.h"

NSString *const TEST_NOTIFICATION_NAME = @"TestNotification";

@implementation TestNotification

-(id)initWithObject:(id)object
{
    object_ = object;
    return self;
}

-(NSString *)name
{
    return TEST_NOTIFICATION_NAME;
}

-(id)object
{
    return object_;
}

- (NSDictionary *)userInfo
{
    return nil;
}

@end

また、NSNotifications に関連する大規模な問題にも注意してください。NSNotification notificationWithName:object:を使用して強化された NSNotification のタイプは、NSNotificationではなく、NSConcreteNotification です。さらに厄介なことに、クラスをチェックしている場合、NSConcreteNotification はプライベートであるため、比較するものは何もありません。

于 2011-09-27T16:27:40.193 に答える
1

userInfo通知を配信するときに引数を渡すことができます。ペイロードを作成して送信してみませんか。

// New file:

@interface NotificationPayload : NSObject
@property (copy, nonatomic) NSString *thing;
@end

@implementation NotificationPayload
@end

// Somewhere posting:

NotificationPayload *obj = [NotificationPayload new];
obj.thing = @"LOL";

[[NSNotificationCenter defaultCenter] postNotificationName:@"Hi" object:whatever userInfo:@{ @"payload": obj }];

// In some observer:

- (void)somethingHappened:(NSNotification *)notification
{
  NotificationPayload *obj = notification.userInfo[@"payload"];
  NSLog(@"%@", obj.thing);
}

終わり。

余談ですが、サブクラス化を意識的に回避することで、コードがよりクリーンで、保守しやすく、変更しやすく、テストしやすく、拡張しやすくなったことを長年にわたって発見してきました。プロトコルやカテゴリを使用して問題を解決できれば、最初に思いついた見掛け倒しのデザインに縛られることはありません。Swift 2.0 プロトコル拡張機能が混在しているため、私たちも本当に笑っています。

于 2015-07-15T11:05:51.173 に答える
1

正確に設定するのではなく、メソッドの実装をオーバーライドして、name必要なものを返すだけです。言い換えると:

- (NSString *)name
{
    return @"Something";
}

initあなたのイニシャライザは問題ないようです —スーパークラスの実装を呼び出さないの例はこれまで見たことがありません。

于 2011-09-27T16:00:12.327 に答える