Core DataでのCopy & PasteをProperty list(Dictionary)を用いて実現する方法

プレゼンテーション


概要

Copy & Pasteの流れは、Copy操作でコピー元となるオブジェクトをNSStringやNSData等のシリアライズ可能な形式にし、NSPasteboardオブジェクトに引き渡します。Paste操作でそのデータからコピーオブジェクトを生成します。

Core Dataでは、コピーの対象となるオブジェクトはNSManagedObjectのインスタンスになります。NSManagedObjectには、Copyで用いるシリアライズ用のメソッドは用意されていないので、何らかの手段を用いて実装する必要があります。

手段として以下の方法が考えられます。

ここでは、Property list(Dictionary)を用いる方法について記述しています。

利点

NSManagedObjectのPropertyをProperty list(Dictionary)に書き出すので、NSManagedObjectと無関係になり、異なるアプリケーション、異なるドキュメントで再利用可能になります。

多くの場合で、最も無難な方法です。

欠点

NSManagedObjectがRelationshipを含む場合、リレーション先のオブジェクトを特定するための何らかの手段を考える必要があります。

関係が複雑である程、特定の手段が煩雑になる事が予想されます。

チュートリアル

プロジェクトの作成

モデルの作成

名前と住所を持つアドレスブック用のモデルを作成します。

Personクラス

- (NSDictionary *)propertyList;
+ (Person *)personWithPropertyList:(NSDictionary *)propertyList managedObjectContext:(NSManagedObjectContext *)context;
-propertyList
Personのname、address PropertyをProperty list(NSDictionary)に書き出します。
- (NSDictionary *)propertyList
{
	NSMutableDictionary *propertyList = [NSMutableDictionary dictionaryWithCapacity:2];
	id object;
	object = ([self name] == nil) ? (id)[NSNull null] : [self name];
	[propertyList setValue:object forKey:@"name"];
	object = ([self address] == nil) ? (id)[NSNull null] : [self address];
	[propertyList setValue:object forKey:@"address"];
	return propertyList;
}
+personWithPropertyList:managedObjectContext:
Property listからPersonオブジェクトを生成します。
-[NSEntityDescription insertNewObjectForEntityForName:]でPersonオブジェクトを生成します。
propertyListからコピー元のname、address propertyの値を取り出し、生成したPersonオブジェクトにセットします。
+ (Person *)personWithPropertyList:(NSDictionary *)propertyList managedObjectContext:(NSManagedObjectContext *)context
{
	id object;
	Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];

	object = [propertyList valueForKey:@"name"];
	object = (object == [NSNull null]) ? nil : object;
	[person setValue:object forKey:@"name"];

	object = [propertyList valueForKey:@"address"];
	object = (object == [NSNull null]) ? nil : object;
	[person setValue:object forKey:@"address"];
	return person;
}

PropertyListCopyAndPaste_AppDelegateクラス

PropertyListCopyAndPaste_AppDelegateクラスが、メインウインドウdelegateになっているので、このクラスにcopy:、paste:メソッドを実装します。データの管理、表示はNSArrayControllerを用いて行います。

@interface PropertyListCopyAndPaste_AppDelegate : NSObject 
{
	.
	.
	.
	IBOutlet NSArrayController *arrayController;
}
- (IBAction)copy:(id)sender;
- (IBAction)paste:(id)sender;
#import "Person.h"
NSString *PersonPBoardType = @"PersonPBoardType";
-copy:の実装
NSPasteboardで扱うデータ形式を-[NSPasteboard declareTypes:owner]で登録します。ここでは、nameの一覧をText形式でも扱える様に2通りのデータ形式を用いる事にします。
-[Person propertyList]でPersonのPropertyをProperty listに書き出し、propertyListArrayに追加します。
propertyListArrayを+[NSArchiver archivedDataWithRootObject:]でシリアライズし、データ形式をPersonPBoardTypeとしてNSPasteboardオブジェクに引き渡します。
- (IBAction)copy:(id)sender
{
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
	NSArray *types = [NSArray arrayWithObjects:PersonPBoardType, NSStringPboardType, nil];
	[pasteboard declareTypes:types owner:self];

	NSArray *selectedObjects = [arrayController selectedObjects];
	NSEnumerator *enumerator = [selectedObjects objectEnumerator];
	Person *person;
	NSMutableArray *propertyListArray = [NSMutableArray arrayWithCapacity:[selectedObjects count]];
	NSString *string = [NSString string];
	while(person = [enumerator nextObject]) {
		[propertyListArray addObject:[person propertyList]];
		string = [NSString stringWithFormat:@"%@%@?n", string, [person name]];
	}
	
	NSData *data = [NSArchiver archivedDataWithRootObject:propertyListArray];
	[pasteboard setData:data forType:PersonPBoardType];
	[pasteboard setString:string forType:NSStringPboardType];
}
-paste:の実装
NSPasteboardオブジェクトからPersonPBoardType形式のデータを取得し、+[NSUnarchiver unarchiveObjectWithData:]でProperty listの配列に戻します。
+[Person personWithPropertyList:managedObjectContext:]でコピーを生成し、NSArrayControllerに追加し、表示される様にします。
- (IBAction)paste:(id)sender
{
	NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
	NSString *availableType = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:PersonPBoardType]];
	if ([availableType isEqualToString:PersonPBoardType]) {
		NSManagedObjectContext *context = [self managedObjectContext];
		NSData *data = [pasteboard dataForType:PersonPBoardType];
		NSArray *array = [NSUnarchiver unarchiveObjectWithData:data];
		NSEnumerator *enumerator = [array objectEnumerator];
		id propertyList;
		while(propertyList = [enumerator nextObject]) {
			[arrayController addObject:[Person personWithPropertyList:propertyList managedObjectContext:context]];
		}
	}
}

ユーザーインターフェイスの作成

テスト

関連

Core Data

Core DataでのCopy & Paste (objectID編)

リファレンス

Copying and Copy and Paste