Ecco un esempio di codice. Ho un oggetto generale e un oggetto da risolvere. L'oggetto Dother deve salvare il suo stato cambiando ogni proprietà.
#import <Foundation/Foundation.h>
@interface GeneralObject : NSObject
+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary;
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary;
- (NSDictionary *)dictionaryValue;
- (NSArray *)allPropertyNames;
@end
implementazione
#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
e dopo tutto quello che hanno Daltri classe, che dovrebbe salvare il suo stato su ogni cambio di qualsiasi proprietà
#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
e l'attuazione
#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
Felice codifica!
Hm. Sembra che io stia abusando del concetto di chiavi dipendenti in questo caso. Suppongo che osserverò ogni proprietà individualmente. Avrei giurato che c'era un modo generico per farlo. Che ne dici di un modo per catturare il nome del messaggio passato a una classe tramite il runtime? – LucasTizma
Non proprio.Basta chiamare la chiave dipendente 'propertiesChanged' o qualcosa del genere e sarà abbastanza preciso. mmalc di Apple in realtà suggerisce questa tecnica nel suo esempio e suggerimenti di Cocoa Bindings: http://homepage.mac.com/mmalc/CocoaExamples/controllers.html ... Per quanto riguarda "il rilevamento del nome del messaggio passato a una classe", I supponi che intendi i messaggi * tutti * inviati a una classe. Ciò richiederebbe un oggetto proxy o l'hooking nella funzione di runtime 'objc_msgSend() ', l'ultimo dei quali sarebbe enormemente lento e hackish e in realtà non ne vale la pena. – Chuck