6

Nói một cách đơn giản, có cách nào để nhận thông báo chung khi bất kỳ thuộc tính nào trong lớp Objective-C bị thay đổi không? Tôi biết tôi có thể sử dụng KVO để theo dõi các thay đổi đặc biệt của tài sản, nhưng tôi có nhu cầu gọi một phương thức cụ thể bất cứ khi nào bất kỳ tin nhắn setProperty: nào được gửi đến lớp học của tôi. Tôi muốn có thể nhận được thông báo chung mà không có bất kỳ mối lo ngại nào về đặc tính nào đã được sửa đổi.Quan sát thay đổi đối với bất kỳ thuộc tính lớp nào trong mục tiêu-C

Nếu nó giúp làm sáng tỏ lý do tại sao tôi muốn làm điều này, tôi đang làm cho sử dụng một số bảng mã di chuyển nhanh chóng tìm thấy ở đây: http://blog.atebits.com/2008/12/fast-scrolling-in-tweetie-with-uitableview/

Một phần của quá trình thực hiện điều này là bất cứ khi nào một tài sản trong một cái nhìn bảng ô được sửa đổi, cần gọi số [ self setNeedsDisplay ]. Tôi không muốn ghi đè lên các phương thức setter cho mọi thuộc tính trong lớp của tôi chỉ để thực hiện cuộc gọi này.

Trả lời

5

Như Chuck ghi chú, bạn có thể tạo khóa phụ thuộc, hoặc tất nhiên bạn có thể trực tiếp quan sát tất cả các thuộc tính (ít công việc hơn là quá tải các bộ định vị).

Sử dụng thời gian chạy Objective-C, nếu bạn chỉ sử dụng thuộc tính, bạn có thể tự động hóa quá trình này bằng cách sử dụng class_copyPropertyList(). Nhưng tôi có lẽ chỉ làm điều này nếu vấn đề này xuất hiện một chút cho bạn. Nếu bạn chỉ có một ví dụ của vấn đề này, nó có thể dễ dàng hơn và an toàn hơn và dễ bảo trì hơn chỉ để trực tiếp quan sát danh sách các thuộc tính trừ khi bạn cảm thấy thích làm việc trong thời gian chạy ObjC.

2

Không chính xác. Bạn có thể tạo một dependent key phụ thuộc vào mọi thuộc tính bạn muốn phơi bày và sau đó quan sát điều đó. Đó là về gần như bạn sẽ nhận được, tôi nghĩ.

+0

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

+0

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

4

Dưới đây là một ví dụ xây dựng tắt của Chuck và Rob gợi ý:

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

quan sát propertiesChanged sẽ cho chúng tôi biết bất cứ lúc nào một tài sản đã thay đổi .

[self.drakeObject addObserver:self 
        forKeyPath:@"propertiesChanged" 
         options:NSKeyValueObservingOptionNew 
         context:nil]; 
0

Đâ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!

Các vấn đề liên quan