Cocoa Core Data วิธีที่มีประสิทธิภาพในการนับเอนทิตี


174

ฉันอ่านมากเกี่ยวกับ Core Data .. แต่วิธีที่มีประสิทธิภาพในการนับจำนวน Entity-Type (เช่น SQL สามารถทำได้ด้วยการเลือก SELECT (1) ... ) ตอนนี้ฉันเพิ่งแก้ไขภารกิจนี้ด้วยการเลือกทั้งหมดด้วยNSFetchedResultsControllerและรับจำนวนNSArray! ฉันแน่ใจว่านี่ไม่ใช่วิธีที่ดีที่สุด ...

คำตอบ:


303

ฉันไม่ทราบว่าการใช้ NSFetchedResultsController เป็นวิธีที่มีประสิทธิภาพที่สุดในการบรรลุเป้าหมายของคุณหรือไม่ (แต่อาจเป็น) รหัสที่ชัดเจนเพื่อรับจำนวนอินสแตนซ์ของกิจการอยู่ด้านล่าง:

// assuming NSManagedObjectContext *moc

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:moc]];

[request setIncludesSubentities:NO]; //Omit subentities. Default is YES (i.e. include subentities)

NSError *err;
NSUInteger count = [moc countForFetchRequest:request error:&err];
if(count == NSNotFound) {
  //Handle error
}

[request release];

1
บน Leopard คุณต้องการใช้ countForFetchRequest: และไม่ executeFetchRequest:
IlDan

และข้ามไปตั้งค่าเพรดิเคต ไม่มีเพรดิเคต: รับออบเจ็กต์ทั้งหมดที่ตรงกับคำอธิบายเอนทิตี
IlDan

4
เพียงแค่ FYI ให้นับ == 0 หากไม่มีผลลัพธ์สำหรับคำขอเฉพาะ NSNotFound = NSIntegerMax ดังนั้น '// ข้อผิดพลาดของฮันเดล' จะไม่ถูกดำเนินการหากไม่มีผลลัพธ์
Intentss

มีการพิมพ์ผิด: setIncludesSubentities? ฉันคิดว่าเอกสารระบุตัวพิมพ์เล็ก "e" ใน "เอนทิตี" มากกว่าตัวพิมพ์ใหญ่ "E" ในโค้ดตัวอย่าง
Mike

2
@LarsSchneider เอกสารสำหรับcountForFetchRequest:error:สถานะที่NSNotFoundส่งคืนในกรณีที่เกิดข้อผิดพลาด โดยทั่วไปแล้วการNSErrorจัดการในการประชุมโกโก้คือมูลค่าของerrไม่ได้กำหนด (และมักจะเป็นอันตราย) หากไม่มีข้อผิดพลาดเกิดขึ้น
Barry Wark

61

เพื่อความชัดเจนคุณจะไม่นับเอนทิตี แต่เป็นกรณีของเอนทิตีเฉพาะ (หากต้องการนับเอนทิตีอย่างแท้จริงให้ถามโมเดลวัตถุที่ถูกจัดการเพื่อนับจำนวนเอนทิตีของมัน)

-countForFetchRequest:จะนับทุกกรณีของกิจการที่กำหนดโดยไม่ต้องเรียกข้อมูลทั้งหมดที่ใช้งาน

ตัวอย่างเช่น:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName: entityName inManagedObjectContext: context]];

NSError *error = nil;
NSUInteger count = [context countForFetchRequest: request error: &error];

[request release];

return count;

32

รวดเร็ว

มันค่อนข้างง่ายที่จะได้รับการนับจำนวนอินสแตนซ์ทั้งหมดของเอนทิตีใน Core Data:

let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "MyEntity")
let count = context.countForFetchRequest(fetchRequest, error: nil)

ฉันทดสอบสิ่งนี้ในเครื่องจำลองที่มีจำนวนวัตถุมากกว่า 400,000 รายการและผลลัพธ์ค่อนข้างเร็ว (แม้ว่าจะไม่ใช่ในทันที)


23

ฉันจะเพิ่มที่จะทำให้มันมีประสิทธิภาพมากขึ้น ... และเนื่องจากเป็นเพียงการนับคุณไม่จำเป็นต้องมีมูลค่าทรัพย์สินใด ๆ และแน่นอนเช่นหนึ่งในตัวอย่างของรหัสข้างต้นคุณไม่จำเป็นต้องมีหน่วยงานย่อย

ดังนั้นรหัสควรเป็นดังนี้:

int entityCount = 0;
NSEntityDescription *entity = [NSEntityDescription entityForName:@"YourEntity" inManagedObjectContext:_managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setIncludesPropertyValues:NO];
[fetchRequest setIncludesSubentities:NO];
NSError *error = nil;
NSUInteger count = [_managedObjectContext countForFetchRequest: fetchRequest error: &error];
if(error == nil){
    entityCount = count;
}

หวังว่ามันจะช่วย


10

ฉันเชื่อว่าวิธีที่ง่ายที่สุดและมีประสิทธิภาพที่สุดในการนับวัตถุคือการกำหนดNSFetchRequestประเภทผลลัพธ์เป็นNSCountResultTypeและดำเนินการด้วยNSManagedObjectContext countForFetchRequest:error:วิธีการ

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
fetchRequest.resultType = NSCountResultType;
NSError *fetchError = nil;
NSUInteger itemsCount = [managedObjectContext countForFetchRequest:fetchRequest error:&fetchError];
if (itemsCount == NSNotFound) {
    NSLog(@"Fetch error: %@", fetchError);
}

// use itemsCount

6

ฉันเขียนวิธีอรรถประโยชน์อย่างง่ายสำหรับ Swift 3 เพื่อดึงจำนวนของวัตถุ

static func fetchCountFor(entityName: String, predicate: NSPredicate, onMoc moc: NSManagedObjectContext) -> Int {

    var count: Int = 0

    moc.performAndWait {

        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entityName)
        fetchRequest.predicate = predicate
        fetchRequest.resultType = NSFetchRequestResultType.countResultType

        do {
            count = try moc.count(for: fetchRequest)
        } catch {
            //Assert or handle exception gracefully
        }

    }

    return count
}

3

ใน Swift 3

  static func getProductCount() -> Int {
    let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Product")
    let count = try! moc.count(for: fetchRequest)
    return count
}

1

เป็นเพียงแค่นี้จริงๆ:

let kBoat = try? yourContainer.viewContext.count(for: NSFetchRequest(entityName: "Boat"))

"เรือ" เป็นเพียงชื่อของเอนทิตีจากหน้าจอโมเดลข้อมูลของคุณ:

ป้อนคำอธิบายรูปภาพที่นี่

โลกyourContainerคืออะไร

หากต้องการใช้ข้อมูลหลักในแอปของคุณในบางครั้งคุณก็สามารถทำได้

var yourContainer = NSPersistentContainer(name: "stuff")

โดยที่ "stuff" เป็นเพียงชื่อของไฟล์โมเดลข้อมูล

ป้อนคำอธิบายรูปภาพที่นี่

คุณเพียงแค่มีซิงเกิลตันสำหรับเรื่องนี้

import CoreData
public let core = Core.shared
public final class Core {
    static let shared = Core()
    var container: NSPersistentContainer!
    private init() {
        container = NSPersistentContainer(name: "stuff")
        container.loadPersistentStores { storeDescription, error in
            if let error = error { print("Error loading... \(error)") }
        }
    }
    
    func saveContext() {
        if container.viewContext.hasChanges {
            do { try container.viewContext.save()
            } catch { print("Error saving... \(error)") }
        }
    }
}

ดังนั้นจากที่ใดก็ได้ในแอพ

core.container

เป็นภาชนะของคุณ

ดังนั้นในทางปฏิบัติเพื่อให้นับจำนวนเอนทิตีใด ๆ มันเป็นเพียง

let k = try? core.container.viewContext.count(for: NSFetchRequest(entityName: "Boat"))

0

หากคุณต้องการค้นหาจำนวนเฉพาะการดึงข้อมูลเฉพาะฉันเชื่อว่านี่เป็นวิธีที่ดีที่สุด:

NSError *err;
NSUInteger count = [context countForFetchRequest:fetch error:&err];

if(count > 0) {
NSLog(@"EXIST"); 
} else {
NSLog(@"NOT exist");
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.