エンティティにタイププロパティを割り当てることができるように、コアデータエンティティを列挙値にバインドする最良の方法は何ですか?言い換えれば、私はと呼ばれるエンティティ持っているItem
とitemType
私は列挙型にバインドしたいというプロパティを、このついて行くの最善の方法は何ですか。
エンティティにタイププロパティを割り当てることができるように、コアデータエンティティを列挙値にバインドする最良の方法は何ですか?言い換えれば、私はと呼ばれるエンティティ持っているItem
とitemType
私は列挙型にバインドしたいというプロパティを、このついて行くの最善の方法は何ですか。
回答:
値を列挙型に制限する場合は、カスタムアクセサーを作成する必要があります。したがって、最初に次のように列挙型を宣言します。
typedef enum {
kPaymentFrequencyOneOff = 0,
kPaymentFrequencyYearly = 1,
kPaymentFrequencyMonthly = 2,
kPaymentFrequencyWeekly = 3
} PaymentFrequency;
次に、プロパティのゲッターとセッターを宣言します。標準のアクセサーはスカラー型ではなくNSNumberオブジェクトを想定しているため、既存のオブジェクトをオーバーライドすることはお勧めできません。バインディングまたはKVOシステムのいずれかで値にアクセスしようとすると、問題が発生します。
- (PaymentFrequency)itemTypeRaw {
return (PaymentFrequency)[[self itemType] intValue];
}
- (void)setItemTypeRaw:(PaymentFrequency)type {
[self setItemType:[NSNumber numberWithInt:type]];
}
最後に、+ keyPathsForValuesAffecting<Key>
itemTypeが変更されたときにitemTypeRawのKVO通知を受け取るように実装する必要があります。
+ (NSSet *)keyPathsForValuesAffectingItemTypeRaw {
return [NSSet setWithObject:@"itemType"];
}
int16_t
ます。
あなたはこの方法で、もっと簡単に行うことができます:
typedef enum Types_e : int16_t {
TypeA = 0,
TypeB = 1,
} Types_t;
@property (nonatomic) Types_t itemType;
また、モデルではitemType
、16ビットの数値に設定します。すべて完了。追加のコードは必要ありません。いつもの中に入れるだけ
@dynamic itemType;
Xcodeを使用してNSManagedObject
サブクラスを作成している場合は、「プリミティブデータ型にスカラープロパティを使用する」設定がオンになっていることを確認してください。
retain
、メモリ管理に関連していないそれはデータベースかに格納されますかどうか。
私が検討している別のアプローチは、列挙型をまったく宣言するのではなく、代わりに値をNSNumberのカテゴリメソッドとして宣言することです。
mogeneratorを使用している場合は、https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-typesをご覧ください。ユーザー情報にの値をitemType
持つと呼ばれる整数16属性を持つことができます。次に、エンティティのユーザー情報で、列挙型が定義されているヘッダーの名前に設定します。ヘッダーファイルを生成すると、mogeneratorは自動的にプロパティにタイプを設定します。attributeValueScalarType
Item
additionalHeaderFileName
Item
Item
私は属性タイプを16ビット整数として設定し、これを使用します:
#import <CoreData/CoreData.h>
enum {
LDDirtyTypeRecord = 0,
LDDirtyTypeAttachment
};
typedef int16_t LDDirtyType;
enum {
LDDirtyActionInsert = 0,
LDDirtyActionDelete
};
typedef int16_t LDDirtyAction;
@interface LDDirty : NSManagedObject
@property (nonatomic, strong) NSString* identifier;
@property (nonatomic) LDDirtyType type;
@property (nonatomic) LDDirtyAction action;
@end
...
#import "LDDirty.h"
@implementation LDDirty
@dynamic identifier;
@dynamic type;
@dynamic action;
@end
列挙型は標準のshortでサポートされているため、NSNumberラッパーを使用して、プロパティをスカラー値として直接設定することもできません。コアデータモデルのデータ型を「整数32」に設定してください。
MyEntity.h
typedef enum {
kEnumThing, /* 0 is implied */
kEnumWidget, /* 1 is implied */
} MyThingAMaBobs;
@interface myEntity : NSManagedObject
@property (nonatomic) int32_t coreDataEnumStorage;
コードの他の場所
myEntityInstance.coreDataEnumStorage = kEnumThing;
または、JSON文字列からの解析またはファイルからの読み込み
myEntityInstance.coreDataEnumStorage = [myStringOfAnInteger intValue];
私はこれを何度も行っており、次のフォームが役立つことがわかりました。
// accountType
public var account:AccountType {
get {
willAccessValueForKey(Field.Account.rawValue)
defer { didAccessValueForKey(Field.Account.rawValue) }
return primitiveAccountType.flatMap { AccountType(rawValue: $0) } ?? .New }
set {
willChangeValueForKey(Field.Account.rawValue)
defer { didChangeValueForKey(Field.Account.rawValue) }
primitiveAccountType = newValue.rawValue }}
@NSManaged private var primitiveAccountType: String?
この場合、列挙型は非常に単純です。
public enum AccountType: String {
case New = "new"
case Registered = "full"
}
ペダンティックと呼びますが、次のようにフィールド名に列挙型を使用します。
public enum Field:String {
case Account = "account"
}
これは複雑なデータモデルでは手間がかかるため、MOM /エンティティを使用してすべてのマッピングを吐き出すコードジェネレーターを作成しました。私の入力は、テーブル/行から列挙型への辞書になります。その間、JSONシリアル化コードも生成しました。非常に複雑なモデルでこれを実行しましたが、時間を大幅に節約できることがわかりました。
以下に貼り付けたコードは私にとってはうまくいき、私はそれを完全に機能する例として追加しました。アプリ全体で幅広く使用するつもりなので、このアプローチについて意見を伺いたい。
@dynamicはそのままにしておきます。プロパティで指定されたゲッター/セッターによって満たされるからです。
iKenndacによる回答に従って、デフォルトのゲッター/セッター名を上書きしていません。
typedefの有効な値にNSAssertを介していくつかの範囲チェックを含めました。
指定されたtypedefの文字列値を取得するメソッドも追加しました。
定数の前に「k」ではなく「c」を付けます。私は「k」(数学の起源、歴史的)の背後にある理由を知っていますが、それを使ってESLコードを読んでいるように感じるので、「c」を使用します。ただ個人的なものです。
ここに同様の質問があります:コアデータ型としてのtypedef
このアプローチについてのご意見をお待ちしています。
Word.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
typedef enum {
cPresent = 0,
cFuturProche = 1,
cPasseCompose = 2,
cImparfait = 3,
cFuturSimple = 4,
cImperatif = 5
} TenseTypeEnum;
@class Word;
@interface Word : NSManagedObject
@property (nonatomic, retain) NSString * word;
@property (nonatomic, getter = tenseRaw, setter = setTenseRaw:) TenseTypeEnum tense;
// custom getter & setter methods
-(void)setTenseRaw:(TenseTypeEnum)newValue;
-(TenseTypeEnum)tenseRaw;
- (NSString *)textForTenseType:(TenseTypeEnum)tenseType;
@end
Word.m
#import "Word.h"
@implementation Word
@dynamic word;
@dynamic tense;
// custom getter & setter methods
-(void)setTenseRaw:(TenseTypeEnum)newValue
{
NSNumber *numberValue = [NSNumber numberWithInt:newValue];
[self willChangeValueForKey:@"tense"];
[self setPrimitiveValue:numberValue forKey:@"tense"];
[self didChangeValueForKey:@"tense"];
}
-(TenseTypeEnum)tenseRaw
{
[self willAccessValueForKey:@"tense"];
NSNumber *numberValue = [self primitiveValueForKey:@"tense"];
[self didAccessValueForKey:@"tense"];
int intValue = [numberValue intValue];
NSAssert(intValue >= 0 && intValue <= 5, @"unsupported tense type");
return (TenseTypeEnum) intValue;
}
- (NSString *)textForTenseType:(TenseTypeEnum)tenseType
{
NSString *tenseText = [[NSString alloc] init];
switch(tenseType){
case cPresent:
tenseText = @"présent";
break;
case cFuturProche:
tenseText = @"futur proche";
break;
case cPasseCompose:
tenseText = @"passé composé";
break;
case cImparfait:
tenseText = @"imparfait";
break;
case cFuturSimple:
tenseText = @"futur simple";
break;
case cImperatif:
tenseText = @"impératif";
break;
}
return tenseText;
}
@end
「YourClass」という名前のエンティティを作成すると、Xcodeは自動的に「クラス定義」を「データモデルインスペクタ」でのCodegenタイプとしてデフォルトで選択します。これにより、以下のクラスが生成されます。
// YourClass+CoreDataClass.swift
@objc(YourClass)
public class YourClass: NSManagedObject {
}
// YourClass+CoreDataClass.h
@interface YourClass : NSManagedObject
@end
#import "YourClass+CoreDataProperties.h"
// YourClass+CoreDataClass.m
#import "YourClass+CoreDataClass.h"
@implementation YourClass
@end
Xcodeの「クラス定義」ではなく、Codegenオプションから「Category / Extension」を選択します。
ここで、列挙型を追加する場合は、自動生成されたクラスに別の拡張機能を作成し、以下のように列挙型定義をここに追加します。
// YourClass+Extension.h
#import "YourClass+CoreDataClass.h" // That was the trick for me!
@interface YourClass (Extension)
@end
// YourClass+Extension.m
#import "YourClass+Extension.h"
@implementation YourClass (Extension)
typedef NS_ENUM(int16_t, YourEnumType) {
YourEnumTypeStarted,
YourEnumTypeDone,
YourEnumTypePaused,
YourEnumTypeInternetConnectionError,
YourEnumTypeFailed
};
@end
値を列挙型に制限したい場合は、カスタムアクセサーを作成できます。質問所有者が受け付けた回答を確認してください。または、以下のようにキャスト演算子を使用して明示的な変換方法で列挙型を設定しながら列挙型を変換できます。
model.yourEnumProperty = (int16_t)YourEnumTypeStarted;
Xcodeは、モデリングツールでNSManagedObjectサブクラスの自動生成をサポートするようになりました。エンティティインスペクターで:
Manual / Noneがデフォルトであり、以前の動作です。この場合、独自のサブクラスを実装するか、NSManagedObjectを使用する必要があります。Category / Extensionは、ClassName + CoreDataGeneratedPropertiesのような名前のファイルにクラス拡張を生成します。メインクラスを宣言/実装する必要があります(Obj-Cの場合、ヘッダーを介して、拡張機能がClassName.hという名前でインポートできます)。クラス定義は、ClassName + CoreDataClassのような名前のサブクラスファイルと、Category / Extension用に生成されたファイルを生成します。生成されたファイルはDerivedDataに配置され、モデルが保存された後の最初のビルドで再構築されます。また、Xcodeによってインデックスが作成されるため、参照をコマンドクリックしてファイル名で高速に開くことができます。
enum
ですか?