今回の内容
前回は、一つのNurseryデータベースを複数のプロセスから使いました。
今回は、NULibraryオブジェクトの基本的な使い方を説明します。
NULibraryクラスとは
NULibraryはB+木を実装したクラスで、NSMutableDictionaryに似た使い方ができます。
キーオブジェクトとそれに対応するオブジェクトのペアの格納、キーオブジェクトに対応するオブジェクトの取得ができます。
また、指定したキー以上(またはより大きい)または以下(またはより小さい)、に対応する範囲のオブジェクトに効率的に順次アクセスする事ができます。
キーとして使用できるオブジェクトはNSComparisonResultを返すcompare:メソッドを実装している必要があります。
もしくは、NUComparatorプロトコルを実装したクラスを定義して、そのインスタンスをNULibraryのインスタンス作成時に指定して、NULibraryオブジェクトのキーオブジェクトの比較方法をカスタマイズすることも可能です。
NULibraryを使うアプリケーションを作成する
プロジェクトを作成する
はじめてのNursery その2 実際に使ってみるを参考に新しいアプリケーションプロジェクトを作成し、Nurseryフレームワークを使用できる様にします。
今回のプロジェクト名はExample-of-NULibraryとしました。
main.mファイルを変更します。
次の様に変更します。
#import <Cocoa/Cocoa.h>
#import <Nursery/Nursery.h>
//Gardenオブジェクトを保持する
static NUGarden *garden = nil;
//NULibraryオブジェクトを保持する
static NULibrary *library = nil;
//Nurseryデータベースが存在しなければNULibraryに数値を追加して保存
//存在すれば、GardenからNULibraryオブジェクトを取得
void saveOrLoadLibrary(void)
{
//データベースを保存するファイルパスを取得
NSString *aFilepath = [NSHomeDirectory() stringByAppendingPathComponent:@"Example-of-NULibrary"];
//ファイルパスを指定してデータベースオブジェクトを作成
NUMainBranchNursery *aNursery = [NUMainBranchNursery nurseryWithContentsOfFile:aFilepath];
//データベースに保存するオブジェクトを管理するオブジェクトを作成
NUGarden *aGarden = [aNursery makeGarden];
if (![aGarden root])
{
//ルートオブジェクトが無ければ新しくNULibraryのインスタンスを作成して保存する
NULibrary *aLibrary = [NULibrary library];
//ここでは、100万個のNSNumberをNULibraryオブジェクトに追加
for (NSUInteger i = 0; i < 1000000; i++)
{
NSNumber *aNumber = @(i);
//ここではキーに対応するオブジェクトにキー自身を設定
[aLibrary setObject:aNumber forKey:aNumber];
}
[aGarden setRoot:aLibrary];
[aGarden farmOut]; //メモリ上のオブジェクトをデータベースファイルに保存
}
//static変数にGardenオブジェクトとLibraryオブジェクトをそれぞれ設定
garden = aGarden;
library = [aGarden root];
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
}
return NSApplicationMain(argc, argv);
}
アプリケーションをビルドして実行します
main.mファイルを変更したら一度アプリケーションを実行し、起動したことを確認後に終了させます。
NULibraryオブジェクトから、キーオブジェクトに対応するオブジェクトを取得し、それらをログ出力して確認します
一つのキーオブジェクトに対応するオブジェクトをログ出力する
次の関数をmain.mファイルのmain関数の前に追加します。
//指定されたキーに対応するオブジェクトをログ出力する
void logObjectForKey(NSNumber *aKey)
{
NSNumber *aNumber = [library objectForKey:aKey];
NSLog(@"number: %@", aNumber); //number: 0
}
main関数を次のように変更します。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
//値が0のNSNumberオブジェクトに対応するオブジェクトをログ出力する
logObjectForKey(@(0));
}
return NSApplicationMain(argc, argv);
}
アプリケーションをビルドして実行します。
Xcodeのコンソールに、number: 0 が出力されます。
指定したキー以下に対応するオブジェクトをログ出力する
次の関数をmain.mファイルのmain関数の前に追加します。
//指定されたキー以下に対応するオブジェクトをログ出力する
void logObjectsLessThanOrEqual(NSNumber *aKey)
{
[library enumerateKeysAndObjectsWithKeyLessThan:aKey orEqual:YES options:0 usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
main関数を次のように変更します。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
//1000以下のキーに対応するオブジェクトをログ出力する
logObjectsLessThanOrEqual(@(1000));
}
return NSApplicationMain(argc, argv);
}
アプリケーションをビルドして実行します。
Xcodeのコンソールに、以下の様に出力されます。
- key: 0, object: 0
- key: 1, object: 1
- key: 2, object: 2
- ...省略
- key: 998, object: 998
- key: 999, object: 999
- key: 1000, object: 1000
指定したキーに対応するオブジェクトを逆順(大きいキーから小さいキーの順番)でログ出力する
次の関数をmain.mファイルのmain関数の前に追加します。
//指定されたキー以下に対応するオブジェクトを逆順(大きいキーから小さいキーの順番)でログ出力する
void logObjectsLessThanOrEqualWithReverseOption(NSNumber *aKey)
{
[library enumerateKeysAndObjectsWithKeyLessThan:aKey orEqual:YES options:NSEnumerationReverse usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
main関数を次のように変更します。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
//1000以下のキーに対応するオブジェクトを逆順(大きいキーから小さいキーの順番)でログ出力する
logObjectsLessThanOrEqualWithReverseOption(@(1000));
}
return NSApplicationMain(argc, argv);
}
アプリケーションをビルドして実行します。
Xcodeのコンソールに、以下の様に出力されます。
- key: 1000, object: 1000
- key: 999, object: 999
- key: 998, object: 998
- ...省略
- key: 2, object: 2
- key: 1, object: 1
- key: 0, object: 0
指定したキー範囲に対応するオブジェクトを順(小さいキーから大きいキーの順番)にログ出力する
次の関数をmain.mファイルのmain関数の前に追加します。
//指定されたキー範囲(小さい方のキーから大きい方のキーの順番)でキーに対応するオブジェクトをログ出力する
void logObjectsFromSmallToBig(NSNumber *aSmallerKey, NSNumber *aBiggerKey)
{
[library enumerateKeysAndObjectsWithKeyGreaterThan:aSmallerKey orEqual:YES andKeyLessThan:aBiggerKey orEqual:YES options:0 usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
main関数を次のように変更します。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
//0以上のキーから10000以下のキーの範囲に対応するオブジェクトを小さいキーから大きいキーの順番でログ出力する
logObjectsFromSmallToBig(@(0), @(10000));
}
return NSApplicationMain(argc, argv);
}
アプリケーションをビルドして実行します。
Xcodeのコンソールに、以下の様に出力されます。
- key: 1000, object: 1000
- key: 999, object: 999
- key: 998, object: 998
- ...省略
- key: 9998, object: 9998
- key: 9999, object: 9999
- key: 10000, object: 10000
指定したキー範囲に対応するオブジェクトを逆順(大きいキーから小さいキーの順番)にログ出力する
次の関数をmain.mファイルのmain関数の前に追加します。
//指定された大きい方のキーから小さい方のキーの順番でキーに対応するオブジェクトをログ出力する
void logObjectsFromBigToSmall(NSNumber *aBiggerKey, NSNumber *aSmallerKey)
{
[library enumerateKeysAndObjectsWithKeyGreaterThan:aSmallerKey orEqual:YES andKeyLessThan:aBiggerKey orEqual:YES options:NSEnumerationReverse usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
main関数を次のように変更します。
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
//10000以下のキーから0以上のキー範囲に対応するオブジェクトを大きいキーから小さいキーの順番でログ出力する
logObjectsFromBigToSmall(@(10000), @(0));
}
return NSApplicationMain(argc, argv);
}
アプリケーションをビルドして実行します。
Xcodeのコンソールに、以下の様に出力されます。
- key: 10000, object: 10000
- key: 9999, object: 9999
- key: 9998, object: 9998
- ...省略
- key: 2, object: 2
- key: 1, object: 1
- key: 0, object: 0
今回作成したmain.mファイル
#import <Cocoa/Cocoa.h>
#import <Nursery/Nursery.h>
//Gardenオブジェクトを保持する
static NUGarden *garden = nil;
//NULibraryオブジェクトを保持する
static NULibrary *library = nil;
//Nurseryデータベースが存在しなければNULibraryに数値を追加して保存
//存在すれば、GardenからNULibraryオブジェクトを取得
void saveOrLoadLibrary(void)
{
//データベースを保存するファイルパスを取得
NSString *aFilepath = [NSHomeDirectory() stringByAppendingPathComponent:@"Example-of-NULibrary"];
//ファイルパスを指定してデータベースオブジェクトを作成
NUMainBranchNursery *aNursery = [NUMainBranchNursery nurseryWithContentsOfFile:aFilepath];
//データベースに保存するオブジェクトを管理するオブジェクトを作成
NUGarden *aGarden = [aNursery makeGarden];
if (![aGarden root])
{
//ルートオブジェクトが無ければ新しくNULibraryのインスタンスを作成して保存する
NULibrary *aLibrary = [NULibrary library];
//ここでは、100万個のNSNumberをNULibraryオブジェクトに追加
for (NSUInteger i = 0; i < 1000000; i++)
{
NSNumber *aNumber = @(i);
//ここではキーに対応するオブジェクトにキー自身を設定
[aLibrary setObject:aNumber forKey:aNumber];
}
[aGarden setRoot:aLibrary];
[aGarden farmOut]; //メモリ上のオブジェクトをデータベースファイルに保存
}
//static変数にGardenオブジェクトとLibraryオブジェクトをそれぞれ設定
garden = aGarden;
library = [aGarden root];
}
//指定されたキーに対応するオブジェクトをログ出力する
void logObjectForKey(NSNumber *aKey)
{
NSNumber *aNumber = [library objectForKey:aKey];
NSLog(@"number: %@", aNumber); //number: 0
}
//指定されたキー以下に対応するオブジェクトをログ出力する
void logObjectsLessThanOrEqual(NSNumber *aKey)
{
[library enumerateKeysAndObjectsWithKeyLessThan:aKey orEqual:YES options:0 usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
//指定されたキー以下に対応するオブジェクトを逆順(大きいキーから小さいキーの順番)でログ出力する
void logObjectsLessThanOrEqualWithReverseOption(NSNumber *aKey)
{
[library enumerateKeysAndObjectsWithKeyLessThan:aKey orEqual:YES options:NSEnumerationReverse usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
//指定されたキー範囲(小さい方のキーから大きい方のキーの順番)でキーに対応するオブジェクトをログ出力する
void logObjectsFromSmallToBig(NSNumber *aSmallerKey, NSNumber *aBiggerKey)
{
[library enumerateKeysAndObjectsWithKeyGreaterThan:aSmallerKey orEqual:YES andKeyLessThan:aBiggerKey orEqual:YES options:0 usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
//指定された大きい方のキーから小さい方のキーの順番でキーに対応するオブジェクトをログ出力する
void logObjectsFromBigToSmall(NSNumber *aBiggerKey, NSNumber *aSmallerKey)
{
[library enumerateKeysAndObjectsWithKeyGreaterThan:aSmallerKey orEqual:YES andKeyLessThan:aBiggerKey orEqual:YES options:NSEnumerationReverse usingBlock:^(id aKey, id anObj, BOOL *aStop) {
NSLog(@"key: %@, object: %@", aKey, anObj);
}];
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
//NULibraryオブジェクトを読み込みまたは保存する
saveOrLoadLibrary();
//値が0のNSNumberオブジェクトに対応するオブジェクトをログ出力する
logObjectForKey(@(0));
//1000以下のキーに対応するオブジェクトをログ出力する
// logObjectsLessThanOrEqual(@(1000));
//1000以下のキーに対応するオブジェクトを逆順(大きいキーから小さいキーの順番)でログ出力する
// logObjectsLessThanOrEqualWithReverseOption(@(1000));
//0以上のキーから10000以下のキーの範囲に対応するオブジェクトを小さいキーから大きいキーの順番でログ出力する
// logObjectsFromSmallToBig(@(0), @(10000));
//10000以下のキーから0以上のキー範囲に対応するオブジェクトを大きいキーから小さいキーの順番でログ出力する
// logObjectsFromBigToSmall(@(10000), @(0));
}
return NSApplicationMain(argc, argv);
}
次回
次回はNurseryデータベースに保存したオブジェクトのクラス定義を変更した場合の処理を紹介する予定です。