Наблюдение за изменением ЛЮБОГО свойства класса в Objective C - PullRequest
6 голосов
/ 16 декабря 2009

Проще говоря, есть ли способ получить общее уведомление при изменении какого-либо свойства в классе Objective-C? Я знаю, что могу использовать KVO для мониторинга конкретных изменений свойств, но мне нужно вызывать определенный метод всякий раз, когда в мой класс отправляется любое сообщение setProperty:. Я хочу получать общее уведомление, не беспокоясь о том, какое именно свойство было изменено.

Если это поможет уточнить, почему я хочу это сделать, я использую некоторый код быстрой прокрутки таблиц, найденный здесь: http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/

Часть процесса достижения этой цели заключается в том, что всякий раз, когда свойство в ячейке табличного представления изменяется, необходимо вызывать [ self setNeedsDisplay ]. Я бы предпочел не переопределять методы установки для каждого свойства в моем классе, просто чтобы сделать этот вызов.

Ответы [ 4 ]

6 голосов
/ 16 декабря 2009

Как отмечает Чак, вы можете создать зависимый ключ или, конечно, вы можете напрямую наблюдать за всеми свойствами (это меньше работы, чем перегрузка сеттеров).

Используя среду выполнения Objective C, если вы используете исключительно свойства, вы можете автоматизировать этот процесс, используя class_copyPropertyList(). Но я бы, наверное, сделал это только в том случае, если эта проблема возникнет немного для вас. Если у вас есть только один экземпляр этой проблемы, возможно, проще, безопаснее и удобнее в обслуживании просто наблюдать список свойств, если только вы не хотите работать во время выполнения ObjC.

4 голосов
/ 16 января 2015

Вот пример, построенный из предложений Чака и Роба:

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];
}

наблюдение свойствChanged даст нам знатьв любое время свойство изменилось.

[self.drakeObject addObserver:self
                   forKeyPath:@"propertiesChanged"
                      options:NSKeyValueObservingOptionNew
                      context:nil];
2 голосов
/ 16 декабря 2009

Не совсем. Вы можете создать зависимый ключ , который зависит от каждого свойства, которое вы хотите показать, и затем наблюдать это. Думаю, это так близко, как только сможешь.

0 голосов
/ 08 октября 2016

Вот пример кода. У меня есть общий объект и другой объект. Другой объект должен сохранять свое состояние при изменении каждого свойства.

#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

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

#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

Удачного кодирования!

...