开发者

What's the point of -primitiveValueForKey:?

-setPrimitiveValue:forKey: won't trigger KVO notifications. But in my brain, KVO only makes sense when something changes. But how can change开发者_Go百科 something when I only access it for read?

-primitiveValueForKey: only gets the object for some key. But it won't modify it. So why would/could this cause KVO notifications when using -valueForKey:?

(Of course there is a point, but I don't see it yet.)


The -primitiveValueForKey: and -setPrimitiveValue:forKey: methods are primarily used by Core Data. In particular, Core Data doesn't just need to know when you're going to modify an attribute; it needs to know when you're going to access it as well, so it can implement faulting.

Thus Core Data adds -{will,did}AccessValueForKey: methods to use in getters, just as -{will,did}ChangeValueForKey: methods exist for use in setters to act as KVO hooks.

However, there's another wrinkle: Core Data actually manages the underlying storage of modeled properties for you as well. So you need some way to manipulate this underlying storage within the barriers established by the -{will,did}{Access,Change}ValueForKey: methods. That's where -primitiveValueForKey: and -setPrimitiveValue:forKey: come in.

This is why the standard pattern for implementing Core Data getters and setters, prior to the existence of @property and @dynamic, looked like this:

// Person.m
#import "Person.h"

@implementation Person

- (NSString *)name {
    [self willAccessValueForKey:@"name"];
    NSString *value = [self primitiveValueForKey:@"name"];
    [self didAccessValueForKey:@"name"];
}

- (void)setName:(NSString *)value {
    [self willChangeValueForKey:@"name"];
    [self setPrimitiveValue:value forKey:@"name"];
    [self didChangeValueForKey:@"name"];
}

@end

Now of course, you can just declare a property and define it as @dynamic if you want Core Data to generate this stuff for you at runtime:

// Person.h
@interface Person : NSManagedObject
@property (nonatomic, readwrite, copy) NSString *name;
@end

// Person.m
#import "Person.h"

@implementation Person
@dynamic name;
@end

There are some situations though where you still want to manipulate the underlying storage without KVO or fault-firing, however. Thus Core Data provides a new way to get at this as well, also built around property declarations and automatic synthesis:

// Person.h
@interface Person : NSManagedObject
@property (nonatomic, readwrite, copy) NSString *name;
@end

// Person.m
#import "Person.h"

@interface Person ()
@property (nonatomic, readwrite, copy) NSString *primitiveName;
@end

@implementation Person
@dynamic name;
@dynamic primitiveName;
@end

Note that I put the class continuation in the .m file; it's not something that code outside Person (or even really code outside -awakeFromInsert and -awakeFromFetch) should touch. But it does let me get at the underlying storage for the "name" property without embedding literal strings in my code, and with the use of the real types.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜