1

CGRect値を保存したいCoreDataエンティティがあります。Core DataにはCGRectがサポートされていないため、x、y、width、heightの4つのfloat属性に分割しました。

私にとってより便利にするためにframe、4つのfloat属性から結合されたCGRectを返すカスタムプロパティを追加します。ところで、私はmogeneratorを使用しています。

@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更新通知を回避するのですか?


編集

変形可能なタイプは良い解決策ですが、依存キーパスを更新する適切な方法を知りたいです。もう1つの例は、とfullNameに依存するプロパティを持つことです。それでも、変更した場合、オブザーバーには2回ではなく1回だけ通知されると思います(1回は変更され、もう1回は変更されます)。もう1つの問題は、最初の通知では、部分的にしか更新が実行されないため、状態に一貫性がないことです。firstNamelastNamefullNamefirstNamelastName

私の元の例は十分ではないと思います。これはどう:

@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 D")よりも更新された最初の名前( "C B"のフルネームで、しかしそのようなフルネームはまったく存在しないため、アプリがクラッシュする可能性があります)が表示されます。

4

1 に答える 1

1

2番目の質問について...私見あなたはそれをもっと注意深く考える必要があります。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)に関して、変換可能なものを使用したくない場合(これが一般的な使用法の1つであっても)、rectへの変更が次のように行われることを「強制」できます全体(つまり、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:あなたの「fullName」の問題について...私はfirstNameとlastNameだけでPersonオブジェクトを作成し、次にカテゴリを作成します

#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 に答える