Đây là ví dụ về mã. Tôi có một đối tượng chung và đối tượng dother. Dother đối tượng phải lưu trạng thái của mình trên thay đổi mỗi tài sản.
#import <Foundation/Foundation.h>
@interface GeneralObject : NSObject
+ (instancetype)instanceWithDictionary:(NSDictionary *)aDictionary;
- (instancetype)initWithDictionary:(NSDictionary *)aDictionary;
- (NSDictionary *)dictionaryValue;
- (NSArray *)allPropertyNames;
@end
thực hiện
#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
và sau khi tất cả chúng ta có dother lớp, mà nên lưu trạng thái của mình trên mỗi thay đổi của bất kỳ tài sản
#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
và thực hiện
#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
Chúc mừng mã hóa!
Hm. Có vẻ như tôi sẽ lạm dụng khái niệm khóa phụ thuộc trong trường hợp này. Tôi cho rằng tôi sẽ chỉ quan sát từng thuộc tính riêng lẻ. Tôi có thể thề rằng có một cách chung chung để làm điều này. Làm thế nào về một cách để bắt tên của tin nhắn được chuyển đến một lớp học thông qua thời gian chạy? – LucasTizma
Không thực sự.Chỉ cần gọi khóa phụ thuộc 'propertiesChanged' hoặc một cái gì đó như thế và nó sẽ khá chính xác. mmalc tại Apple thực sự gợi ý kỹ thuật này trong ví dụ và gợi ý về Cocoa Bindings của bạn: http://homepage.mac.com/mmalc/CocoaExamples/controllers.html ... Còn về "bắt tên của thông điệp được chuyển đến một lớp", tôi giả sử bạn có nghĩa là bắt * tất cả * tin nhắn được gửi đến một lớp học. Điều này sẽ yêu cầu hoặc là một đối tượng proxy hoặc hooking vào hàm 'objc_msgSend()' runtime, hàm thứ hai trong số đó sẽ được làm chậm và tấn công và thực sự không đáng. – Chuck