6

簡単に言えば、Objective-C クラスのプロパティが変更されたときに一般的な通知を受け取る方法はありますか? setProperty:KVO を使用して特定のプロパティの変更を監視できることはわかっていますが、クラスにメッセージが送信されるたびに特定のメソッドを呼び出す必要があります。特にどのプロパティが変更されたかを気にすることなく、一般的な通知を受け取ることができるようにしたいと考えています。

これを行う理由を明確にするのに役立つ場合は、ここにある高速テーブルスクロールコードを使用しています: http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview /

これを実現するプロセスの一部として、テーブル ビュー セルのプロパティが変更されるたびに、[ self setNeedsDisplay ]を呼び出す必要があります。この呼び出しを行うためだけに、クラス内のすべてのプロパティのセッター メソッドをオーバーライドする必要はありません。

4

4 に答える 4

6

Chuck が指摘しているように、依存キーを作成することも、もちろんすべてのプロパティを直接監視することもできます (これは、セッターをオーバーロードするよりも手間がかかりません)。

Objective-C ランタイムを使用して、プロパティのみを使用する場合は、 を使用してこのプロセスを自動化できますclass_copyPropertyList()。しかし、この問題が少し発生した場合にのみ、これを行うでしょう。この問題のインスタンスが 1 つしかない場合は、ObjC ランタイムで作業したくない場合を除き、プロパティのリストを直接観察する方がおそらく簡単で安全であり、保守しやすいでしょう。

于 2009-12-15T21:32:13.507 に答える
4

Chuck と Rob の提案から構築された例を次に示します。

DrakeObject.h

@interface DrakeObject : NSObject

@property (nonatomic, strong) NSNumber *age;
@property (nonatomic, strong) NSNumber *money;
@property (nonatomic, strong) NSString *startPosition;
@property (nonatomic, strong) NSString *currentPosition;
@property (nonatomic, strong, readonly) id propertiesChanged;

@end

DrakeObject.m

@implementation DrakeObject

- (instancetype)init {
    self = [super init];
    if (self) {
        self.age = @25;
        self.money = @25000000;
        self.startPosition = @"bottom";
        self.currentPosition = @"here";
    }
    return self;
}

- (id)propertiesChanged {
    return nil;
}

+(NSSet *)keyPathsForValuesAffectingPropertiesChanged {
    return [NSSet setWithObjects:@"age", @"money", @"startPosition", @"currentPosition", nil];
}

propertiesChanged を監視すると、プロパティが変更されたときにいつでも通知されます。

[self.drakeObject addObserver:self
                   forKeyPath:@"propertiesChanged"
                      options:NSKeyValueObservingOptionNew
                      context:nil];
于 2015-01-16T17:26:13.447 に答える
2

ではない正確に。公開するすべてのプロパティに依存する依存キーを作成し、それを観察できます。それはあなたが得るのと同じくらい近いと思います。

于 2009-12-15T21:19:42.503 に答える
0

ここにコードの例を示します。一般オブジェクトとドザー オブジェクトがあります。Dother オブジェクトは、各プロパティの変更時に状態を保存する必要があります。

#import <Foundation/Foundation.h>

@interface GeneralObject : NSObject

+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary;
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary;
- (NSDictionary *)dictionaryValue;
- (NSArray *)allPropertyNames;

@end

実装

#import "GeneralObject.h"
#import <objc/runtime.h>

@implementation GeneralObject

#pragma mark - Public

+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary {
    return [[self alloc] initWithDictionary:aDictionary];
}

- (instancetype)initWithDictionary:(NSDictionary *)aDictionary {
    aDictionary = [aDictionary clean];

    for (NSString* propName in [self allPropertyNames]) {
        [self setValue:aDictionary[propName] forKey:propName];
    }

    return self;
}

- (NSDictionary *)dictionaryValue {
    NSMutableDictionary *result = [NSMutableDictionary dictionary];
    NSArray *propertyNames = [self allPropertyNames];

    id object;
    for (NSString *key in propertyNames) {
        object = [self valueForKey:key];
        if (object) {
            [result setObject:object forKey:key];
        }
    }

    return result;
}

- (NSArray *)allPropertyNames {
    unsigned count;
    objc_property_t *properties = class_copyPropertyList([self class], &count);

    NSMutableArray *array = [NSMutableArray array];

    unsigned i;
    for (i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        NSString *name = [NSString stringWithUTF8String:property_getName(property)];
        [array addObject:name];
    }

    free(properties);

    return array;
}

@end

結局のところ、dother クラスがあり、プロパティが変更されるたびに状態を保存する必要があります。

#import "GeneralObject.h"

extern NSString *const kUserDefaultsUserKey;

@interface DotherObject : GeneralObject

@property (strong, nonatomic) NSString *firstName;
@property (strong, nonatomic) NSString *lastName;
@property (strong, nonatomic) NSString *email;

@end

と実装

#import "DotherObject.h"

NSString *const kUserDefaultsUserKey = @"CurrentUserKey";

@implementation DotherObject

- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
    if (self = [super initWithDictionary:dictionary]) {
        for (NSString *key in [self allPropertyNames]) {
            [self addObserver:self forKeyPath:key options:NSKeyValueObservingOptionNew context:nil];
        }
    }

    return self;
}

- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context {
    NSDictionary *dict = [self dictionaryValue];
    [[NSUserDefaults standardUserDefaults] setObject:dict forKey:kUserDefaultsUserKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (NSString *)description {
    return [NSString stringWithFormat:@"%@; dict:\n%@", [super     description], [self dictionaryValue]];
}

@end

ハッピーコーディング!

于 2016-10-07T22:32:00.583 に答える