1

我有一个要存储 CGRect 值的核心数据实体。因为没有对 Core Data 的 CGRect 支持,所以我只是将其拆分为四个浮点属性:x、y、宽度、高度。

为了让我更方便,我添加了一个自定义属性frame,它从四个浮点属性返回组合的 CGRect。顺便说一句,我正在使用发电机。

@interface ViewableData : _ViewableData

@property (nonatomic) CGRect frame;

@end

@implementation ViewableData

- (void)setFrame:(CGRect)frame {
    if (frame.origin.x != self.xValue)
        self.xValue = frame.origin.x;
    if (frame.origin.y != self.yValue)
        self.yValue = frame.origin.y;
    if (frame.size.width != self.widthValue)
        self.widthValue = frame.size.width;
    if (frame.size.height != self.heightValue)
        self.heightValue = frame.size.height;
}

- (CGRect)frame {
    return CGRectMake(self.xValue, self.yValue, self.widthValue, self.heightValue);
}

+ (NSSet *)keyPathsForValuesAffectingFrame {
    return [NSSet setWithObjects:ViewableDataAttributes.height, ViewableDataAttributes.width, ViewableDataAttributes.x, ViewableDataAttributes.y, nil];
}

@end

它按我的预期工作,但我发现 KVO 观察者收到的通知次数超过了它需要的次数。设置一个框架可能会通知观察者 4 次。是不是要避免不必要的 KVO 更新通知?


编辑

看起来 Transformable 类型是一个很好的解决方案,但我仍然想知道更新依赖键路径的正确方法。另一个例子是拥有fullName一个依赖于firstNameand的属性lastName。不过,如果我改变fullName了,我只希望观察者只收到一次通知而不是两次(一次firstName更改,一次lastName更改)。另一个问题是,在第一次通知时,状态不一致,因为只执行了部分更新。

我认为我原来的例子不够好。这个怎么样:

@interface Person : NSManagedObject

@property (copy, nonatomic) NSString fullName;
@property (copy, nonatomic) NSString firstName;
@property (copy, nonatomic) NSString lastName;    

@end

@implementation Person
@dynamic firstName;
@dynamic lastName;

- (void)setFullName:(NSString *)fullName {
    NSArray *names = [fullName componentsSeparatedByString:@" "];
    self.firstName = names[0];
    self.lastName = names[1];
}

- (CGRect)fullName {
    return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

+ (NSSet *)keyPathsForValuesAffectingFrame {
    return [NSSet setWithObjects:@"firstName", @"lastName", nil];
}

@end

那么如果我这样做

person = // get Person object
person.firstName = @"A";
person.lastName = @"B";
// person.fullName is now "A B"

person.fullName = @"C D";

在最后一行,观察者将看到拳头名称更新(全名“C B”,但这样的全名根本不存在,这可能会使我的应用程序崩溃)而不是姓氏更新(“C D”)

4

1 回答 1

1

关于你的第二个问题......恕我直言,你需要更仔细地考虑它。如果您只有 firstName 的观察者并且您更新 fullName 怎么办?你想通知观察者吗?

顺便说一句:我认为您应该使用setPrimitiveValue:forKey:primitiveValueForKey:手动触发通知..

例如

- (void)setFullName:(NSString *)fullName {
    NSArray *names = [fullName componentsSeparatedByString:@" "];
    [self willChangeValueForKey:@"fullName"];
    [self setPrimitiveValue:names[0] forKey:@"firstName"];
    [self setPrimitiveValue:names[1] forKey:@"lastName"];
    [self didChangeValueForKey:@"fullName"];
}

这样,您只会触发 fullName 的通知,而不是 firstName 和 lastName

编辑:好的..关于您的第一个问题(CGRect),如果您不想使用可变形的(即使这是它们的常见用途之一)并且您可以“强制”对矩形进行修改整体(也就是说,您永远不会调用 xValue 等。直接,您可以将 setFrame 编写为:

- (void)setFrame:(CGRect)frame {
    [self willChangeValueForKey:@"frame"];
    if (frame.origin.x != self.xValue)
        [self setPrimitiveValue:frame.origin.x forKey:@"xValue"];
    if (frame.origin.y != self.yValue)
        [self setPrimitiveValue:frame.origin.y forKey:@"yValue"];
    if (frame.size.width != self.widthValue)
        [self setPrimitiveValue:frame.size.width forKey:@"widthValue"];
    if (frame.size.height != self.heightValue)
        [self setPrimitiveValue:frame.size.height forKey:@"heightValue"];
    [self didChangeValueForKey:@"frame"];
}

EDIT2:关于你的“全名”问题......我会创建一个只有名字和姓氏的人对象,然后是一个类别

#import "Person.h"

@interface Person (FullName)
@property (nonatomic, strong) NSString* fullName;
@end

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

@implementation Person (FullName)
- (NSString*)fullName
{
   return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

- (void)setFullName:(NSString*)fullName
{
    NSArray *names = [fullName componentsSeparatedByString:@" "];
    [self willChangeValueForKey:@"fullName"];
    [self willChangeValueForKey:@"firstName"];
    [self willChangeValueForKey:@"lastName"];
    [self setPrimitiveValue:names[0] forKey:@"firstName"];
    [self setPrimitiveValue:names[1] forKey:@"lastName"];
    [self didChangeValueForKey:@"lastName"];
    [self didChangeValueForKey:@"firstName"];
    [self didChangeValueForKey:@"fullName"];
} 
@end
于 2013-01-19T11:53:12.647 回答