web-dev-qa-db-ja.com

Core Dataの最初のレコードのみをフェッチするにはどうすればよいですか?

Core Dataを使用していて、データセットの最初のレコードのみをフェッチしたいのですが、可能ですか?

39
Boon

NSFetchRequestでsetFetchLimit:メソッドを使用して、フェッチされるレコードの数を制限できます。したがって、最初のレコードのみが必要な場合:

// Given some existing NSFetchRequest *request and NSManagedObjectContext *context:
[request setFetchLimit:1];
NSError *error;
NSArray *results = [context executeFetchRequest:request error:&error];

executeFetchRequest:error:の呼び出しでもNSArrayが返されることに注意してください。サイズ1の配列であっても、操作する前に最初のオブジェクトを配列からプルする必要があります。

別の効率の悪い方法:ストアのタイプによっては、フェッチを制限するとパフォーマンスが劇的に向上する場合があります。ただし、そうでない場合、またはパフォーマンスについてそれほど心配しておらず、後でさらに多くのデータを使用する可能性がある場合は、事前に最初のオブジェクトを配列からプルすることができます。

// Given some existing result NSArray *results:
NSManagedObject *firstManagedObject = [results firstObject];

配列にオブジェクトが含まれていることが確実な場合は、次のようにして、配列を別の配列(たとえば、UITableViewControllerで使用する)に入れることもできます。

// Again, with some NSArray *results:
NSArray *singleObjectResult = [results subarrayWithRange:NSMakeRange(0, 1)];
75
Tim

もちろん、それはあなたが「最初のレコード」によって何を意味するかによります。フェッチ制限を1に設定するだけでなく、フェッチで結果をソートする必要がある場合もあります。

たとえば、データベースに多数のUserオブジェクトがあり、アカウントを作成した最初のオブジェクトを見つけたいと考えています。 (Userという名前の属性を含む、accountCreatedDateのモデルがすでにあると仮定します。)

NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"accountCreatedDate" ascending:YES]; // ascending YES = start with earliest date

NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = entity;
request.sortDescriptors = @[ sortDescriptor ];
request.fetchLimit = 1;

NSError *error;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:request error:&error];

User *result = fetchResults.firstObject; // nil on failure; check value of 'error'

フェッチを制限する前に結果をソートしないと、「最初に」返される結果がわかりません。

13
Craig McMahon

Objective-Cカテゴリを使用して、firstInManagedObjectContext:というNSManagedObjectクラスメソッドを追加しました。

ソースコード

// NSManagedObject+Additions.h

@interface NSManagedObject (Acani)

+ (NSString *)entityName;
+ (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context;
+ (NSManagedObject *)firstInManagedObjectContext:(NSManagedObjectContext *)context;

@end


// NSManagedObject+Additions.m

#import "NSManagedObject+Additions.h"

@implementation NSManagedObject (Acani)

+ (NSString *)entityName {
    return NSStringFromClass([self class]);
}

+ (NSEntityDescription *)entityInManagedObjectContext:(NSManagedObjectContext *)context {
    return [NSEntityDescription entityForName:self.entityName inManagedObjectContext:context];
}

+ (NSManagedObject *)firstInManagedObjectContext:(NSManagedObjectContext *)context {
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    [fetchRequest setEntity:[self entityInManagedObjectContext:context]];
    [fetchRequest setFetchLimit:1];

    NSError *error;
    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
    [fetchRequest release];
    if (fetchedObjects == nil) {
        NSLog(@"Fetch sender error %@, %@", error, [error userInfo]);
        return nil;
    } else if ([fetchedObjects count] > 0) {
        return [fetchedObjects objectAtIndex:0];
    }
    return nil;
}

@end

使用法

これらのファイルをプロジェクトに追加し、必ずターゲットにリンクしてください。次に、#import "NSManagedObject+Additions.h"クラスメソッドを使用する.mファイルのfirstInManagedObjectContext:を使用します。

NSManagedObjectContextの具象(抽象ではない)サブクラスから呼び出します。管理対象オブジェクトを取得するNSManagedObjectContext *contextを渡すだけです。このメソッドは、呼び出されたクラスの名前から(NSString *)entityNameを検出します。クリーンビルドの結果をキャストすることを忘れないでください(警告なし)。

保存したインスタンスが1つしかないことがわかっている管理オブジェクトクラスにこれを使用しています。保存されたインスタンスが複数ある場合は、@ Craig McMahonが示唆するように、NSSortDescriptorを追加できます。すべてのオブジェクトが同じデバイスで作成されている場合は、objectIDではなくaccountCreatedDateで並べ替えることもできます。ただし、オブジェクトIDが順序付けられているかどうかはわかりません。

Eventから派生したNSManagedObjectContextオブジェクトがあるとします。あなたがすることができます:

Event *event = (Event *)[Event firstInManagedObjectContext:context];

ブロック

プラグマティックスタジオのiOS 4ブロックチュートリアル を読んだ後、別の関数を追加して+ fetchと呼び、NSFetchRequestBlockを追加することで、このコードを改善し、さらにモジュール化できることに気付きましたfetchRequestを引数として)&NSFetchRequestFailureBlockを引数として使用して、フェッチ要求をカスタマイズし、フェッチ要求エラーの処理をそれぞれカスタマイズします。私はそれに取り組むようにあなたに挑戦します! :)

2
ma11hew28

fetchLimitNSFetchRequestプロパティを1に設定し、NSArrayメソッドを使用して、結果から最初の要素をfirstObjectで取得し、index out of bound for empty arrayエラー。

次にコード例を示します。

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"ENTITY_NAME" inManagedObjectContext:yourMoc];
NSPedicate *predicate = [NSPredicate predicateWithFormat:@"PREDICATE FORMAT"];
[request setEntity:entity];
[request setPredicate:predicate];
[request setFetchLimit:1];

NSError *error;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
NSManagedObject *object = [results firstObject];
if (object) {
    // there is at least one object matching you predicate
} else {
    // there is no object matching your predicate in the moc
}
2
dulgan

これが私の試みです。 N.B.ブックエンティティはNSManagedObjectから継承します。

NSPredicate *predicate = [NSPredicate predicateWithFormat: @"isbn ==9780786660506"];

Book *book = (Book*) [CoreDataHelper getEntityFromFetchedResultsController:@"Book" :predicate :nil :YES :application.managedObjectContext];


if (book !=nil)    NSLog(@"book entity %@",book.title);

CoreDataHelperという静的ヘルパークラスでこれを強打します。

+ (NSManagedObject*)getEntityFromFetchedResultsController: (NSString*) entityName : (NSPredicate *) predicate : (NSString*) sortKey : (BOOL) sortAscending : (NSManagedObjectContext *) managedObjectContext
{

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext];
[request setEntity:entity]; 
[request setFetchLimit:1];

// If a predicate was passed, pass it to the query
if(predicate != nil)
{
    [request setPredicate:predicate];
}

// If a sort key was passed, use it for sorting.
if(sortKey != nil)
{
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:sortKey ascending:sortAscending];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [request setSortDescriptors:sortDescriptors];
    [sortDescriptors release];
    [sortDescriptor release];
}

NSError *error;

NSMutableArray *mutableFetchResults = [[[managedObjectContext executeFetchRequest:request error:&error] mutableCopy] autorelease];


    if (error !=nil){
NSLog(@"error %@", error);
}
   if ([mutableFetchResults count] >0)
    {
   NSManagedObject *firstObject = [mutableFetchResults objectAtIndex:0];
   return firstObject;
    }else
    {
      return nil;
    }

}    
0
johndpope