LoginSignup
21
20

More than 5 years have passed since last update.

CoreDataにenumの値を入れる

Last updated at Posted at 2014-04-08

前から疑問だったのですが、Core Data Programming Guideにやり方が書いてありました。ていうか先月の3月10日に追記されたっぽいです。

Scalar Valuesっていうところに書いてあります。

追記
コメントで @ishkawa@github さんに教えてもらいましたが、enumの場合はもっと簡単というか普通に実装する方法があるみたいでした。Core Data Programming Guideに書いてあるのは、doubleやCGRectを入れる場合の方法みたいですね。ishkawaさんありがとうございました!

何がしたいのか

たとえばこういう列挙型を定義したとして…。

typedef NS_ENUM(NSUInteger, kServiceType) {
    kServiceTypeUnkown,
    kServiceTypeTwitter,
    kServiceTypeFacebook,
    kServiceTypeTk,
};

こいつをCoreDataのオブジェクトで使いたくてInteger16とかの属性を作っても、アクセスする時のインターフェイスはNSNumberなのでどっかで変換したりしないといけなくてわずらわしい感じでした。ベストプラクティスってなんだろうと毎回疑問に思っていたのです。

公式のドキュメントに書いてあったやり方が簡単だったので、記録しておきます。CGRectとかも同じようにできるみたいでなかなか良い感じです。

モデルの属性

普通に数値を入れる場合と同じく Type Integer16 とかいう感じにします。たとえばservieTypeという名前にでもしておきましょう。

スクリーンショット 2014-04-08 16.42.10.png

カスタムクラス

普通にNSManagedObjectを継承したクラスを作った上で、一部を変更します。クラスの外部にはenumで定義した列挙型を指定しておきます。

diff -up -ur old/SMService.h new/SMService.h
--- old/SMService.h     2014-04-08 16:46:44.000000000 +0900
+++ new/SMService.h     2014-04-08 16:46:29.000000000 +0900
@@ -6,5 +6,5 @@
 @interface SMService : NSManagedObject

 @property (nonatomic, retain) NSString * account;
-@property (nonatomic, retain) NSNumber * serviceType;
+@property (nonatomic) kServiceType serviceType;
 @end

CoreDataが自動的にprimitiveなんとかっていうメソッドを作ってくれているので、それを使ってデータの読み書きをします。警告が出るので、カテゴリで宣言を追加しておきます。

diff -up -ur old/SMService.m new/SMService.m
--- old/SMService.m     2014-04-08 16:46:48.000000000 +0900
+++ new/SMService.m     2014-04-08 16:46:32.000000000 +0900
@@ -1,9 +1,30 @@

 #import "SMService.h"

+@interface SMService (PrimitiveAccessors)
+@property (nonatomic) NSNumber *primitiveServiceType;
+@end
+
 @implementation SMService

 @dynamic account;
 @dynamic serviceType;

+- (kServiceType)serviceType {
+    [self willAccessValueForKey:@"serviceType"];
+
+    NSNumber *tmpValue = [self primitiveServiceType];
+    [self didAccessValueForKey:@"serviceType"];
+
+    return (tmpValue != nil) ? [tmpValue intValue] : kServiceTypeUnkown;
+}
+
+- (void)setServiceType:(kServiceType)value {
+    NSNumber *temp = @(value);
+
+    [self willChangeValueForKey:@"serviceType"];
+    [self setPrimitiveServiceType:temp];
+    [self didChangeValueForKey:@"serviceType"];
+}
+
 @end

たったこれだけの変更で直接enumの値を使えるようになりました。

SELECTする時のやり方は別に変わらないのかな。

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntity:[SMService class] context:context];
[request setPredicate:[NSPredicate predicateWithFormat:@"serviceType == %d", kServiceTypeTwitter]];
NSArray *objects = [context executeFetchRequest:request error:&error];
21
20
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
20