2015-10-22 3 views
-1

NSFetchResultController с NSFetchRequest с fetchBatchSize = 20 всегда возвращает все сущности. Что это может быть? Я не использовал sectionKeyPath и пробовал разные дескрипторы сортировки, но он все равно возвращает все объекты.Основные данные NSFetchResultController размер партии

Спасибо за ответы! Объясню подробности. У меня есть сущность с двумя полями - расстояние и время. Я создал NSFetchResultController:.

func noticesFetcher() -> NSFetchedResultsController { 

    let fetchRequest = NSFetchRequest() 

    let defaultStore = RKManagedObjectStore.defaultStore() 

    let entity = NSEntityDescription.entityForName("Notice", inManagedObjectContext: defaultStore.mainQueueManagedObjectContext) 
    fetchRequest.entity = entity 

    let distanceSortDescriptor = NSSortDescriptor(key: "distance", ascending: true) 
    let timeSortDescriptor = NSSortDescriptor(key: "time", ascending: false) 
    let sortDescriptors = [distanceSortDescriptor, timeSortDescriptor] 
    fetchRequest.sortDescriptors = sortDescriptors 

    fetchRequest.fetchBatchSize = 20 

    let resultFetcher = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: defaultStore.mainQueueManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil) 

    return resultFetcher 
} 

Но когда я выполняю сборщик я всегда все мои объекты в базе данных (100)

func performFetcher(fetcher: NSFetchedResultsController?, filter: NSPredicate?, success: (() ->())?, failure: ((NSError) -> (NSError))?) -> Bool { 

    NSFetchedResultsController.deleteCacheWithName(nil) 

    var resultPerform = false 

    fetcher?.fetchRequest.predicate = filter 

    do { 
     try fetcher?.performFetch() 
     resultPerform = true 
     if success != nil { 
      success!(); 
     } 
    } 
    catch let error as NSError { 
     if failure != nil { 
      failure!(error) 
     } 
    } 

    return resultPerform 
} 

Что это может быть? Результат, который я хочу получить, - это разбиение на страницы. Я знаю, что могу сделать это через ограничение и смещение, но какая проблема здесь? Thanks

ответ

2

Ну, это зависит от того, что вы подразумеваете под «возвратом всех сущностей». Я сомневаюсь, что он возвращает массив, заполненный всеми реализованными объектами.

Размер партии будет отображать (в вашем случае) только 20 объектов за раз. Перейдите и посмотрите на набор зарегистрированных объектов для MOC, и вы можете легко проверить, что происходит.

Вы также можете запускать инструменты и смотреть, как происходит выбор отдельных данных ядра.

Нет, размер партии выборки не «всего 20 объектов», он извлекает ВСЕ объекты. ? Можете ли вы сделать тестовый проект и протестировать этот размер партии я уверен, что вы будете иметь один и тот же вопрос - серд

@Serd, Ответ провайдеров здесь, чтобы помочь вам, и мы иногда неправильно. Если вы сомневаетесь в их ответе, то вы,, должны создать тестовый пример, который показывает, правильно ли они говорят. Почему в мире они должны уделять больше времени, чтобы сделать это, когда вы тот, у кого есть проблема, и это те, кто свободно предлагает помощь?

Если вы сомневаетесь в ответе, то вы выполните, и если вы найдете ответ на свой вопрос по ошибке, укажите либо исправление, либо подтверждение того, что ответ неверен.

Однако вы новичок здесь, и в надежде, что вы сможете извлечь уроки из этого опыта, я дам вам краткую демонстрацию.

Установите MOC для теста, добавив NUM_OBJECTS экземпляров в базу данных.

NSUInteger const NUM_OBJECTS = 1000; 
NSUInteger const INIT_BATCH_SIZE = 100; 

- (void)setUp { 
    [super setUp]; 
    helper = [[TestHelper alloc] init]; 
    url = [[[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]] URLByAppendingPathComponent:@"foo.sqlite"]; 
    [[NSFileManager defaultManager] createDirectoryAtURL:[url URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:NULL]; 
    @autoreleasepool { 
     NSEntityDescription *noticeEntity = [[NSEntityDescription alloc] init]; 
     noticeEntity.name = @"Notice"; 
     NSAttributeDescription *distance = [[NSAttributeDescription alloc] init]; 
     distance.name = @"distance"; 
     distance.attributeType = NSDoubleAttributeType; 
     NSAttributeDescription *time = [[NSAttributeDescription alloc] init]; 
     time.name = @"time"; 
     time.attributeType = NSDoubleAttributeType; 
     noticeEntity.properties = @[distance, time]; 
     NSManagedObjectModel *model = [[NSManagedObjectModel alloc] init]; 
     model.entities = @[noticeEntity]; 

     NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model]; 
     [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:NULL]; 
     moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
     moc.persistentStoreCoordinator = psc; 
     for (NSUInteger count = 0; count < NUM_OBJECTS;) { 
      @autoreleasepool { 
       for (NSUInteger batchCount = 0; batchCount < INIT_BATCH_SIZE && count < NUM_OBJECTS; ++batchCount, ++count) { 
        NSManagedObject *notice = [NSEntityDescription insertNewObjectForEntityForName:@"Notice" inManagedObjectContext:moc]; 
        double distance = ((double)arc4random_uniform(100000))/(arc4random_uniform(100)+1); 
        double time = distance/(arc4random_uniform(100)+1); 
        [notice setValue:@(distance) forKey:@"distance"]; 
        [notice setValue:@(time) forKey:@"time"]; 
       } 
       [moc save:NULL]; 
       [moc reset]; 
      } 
     } 
     [moc save:NULL]; 
     [moc reset]; 
    } 
} 

Cleanup после испытания ...

- (void)tearDown { 
    [super tearDown]; 
    [[NSFileManager defaultManager] removeItemAtURL:[url URLByDeletingLastPathComponent] error:NULL]; 
} 

Несколько вспомогательных методов ...

- (NSArray*)executeFetchWithBatchSize:(NSUInteger)batchSize { 
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Notice"]; 
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:YES], 
            [NSSortDescriptor sortDescriptorWithKey:@"time" ascending:NO]]; 
    fetchRequest.fetchBatchSize = batchSize; 
    return [moc executeFetchRequest:fetchRequest error:NULL]; 
} 

- (NSUInteger)numberOfFaults { 
    NSUInteger numFaults = 0; 
    for (NSManagedObject *object in moc.registeredObjects) { 
     if (object.isFault) ++numFaults; 
    } 
    return numFaults; 
} 

тест для использования размера пакета по умолчанию

- (void)testThatFetchRequestWitDefaultBatchSizeFetchesEverything { 
    XCTAssertEqual(0, moc.registeredObjects.count); 

    NSArray *fetched = [self executeFetchWithBatchSize:0]; 

    XCTAssertEqual(NUM_OBJECTS, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, fetched.count); 
    XCTAssertEqual(NUM_OBJECTS, [self numberOfFaults]); 

    [[fetched objectAtIndex:1] valueForKey:@"distance"]; 
    XCTAssertEqual(NUM_OBJECTS, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, fetched.count); 
    XCTAssertEqual(NUM_OBJECTS-1, [self numberOfFaults]); 
} 

тест для использования не по умолчанию размера пакета

- (void)testThatFetchRequestWithExplicitBatchSizeOnlyFetchesTheNumberRequested { 
    XCTAssertEqual(0, moc.registeredObjects.count); 

    NSUInteger const BATCH_SIZE = 20; 
    NSArray *fetched = [self executeFetchWithBatchSize:BATCH_SIZE]; 

    XCTAssertEqual(0, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, fetched.count); 
    XCTAssertEqual(0, [self numberOfFaults]); 

    [[fetched objectAtIndex:1] valueForKey:@"distance"]; 
    XCTAssertEqual(BATCH_SIZE, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, fetched.count); 
    XCTAssertEqual(BATCH_SIZE-1, [self numberOfFaults]); 
} 

Спасибо за код! Но у меня есть проблемы с NSFetchResultController и его NSFetchRequest, которые имеют пакетную размера (Это извлекает все объекты -. Серд

Привычки живучи Вместо того, чтобы это утверждение, вы должны были взять код я дал вам и немного изменил его, чтобы проверить с помощью выбранного контролера результатов, и тогда вы подтвердите, что ваше утверждение «Он извлекает все сущности» неверно. Например ...

Изменить помощников только ...

- (NSFetchRequest*)fetchRequestWithBatchSize:(NSUInteger)batchSize { 
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Notice"]; 
    fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"distance" ascending:YES], 
            [NSSortDescriptor sortDescriptorWithKey:@"time" ascending:NO]]; 
    fetchRequest.fetchBatchSize = batchSize; 
    return fetchRequest; 
} 

- (NSArray*)executeFetchWithBatchSize:(NSUInteger)batchSize { 
    return [moc executeFetchRequest:[self fetchRequestWithBatchSize:batchSize] error:NULL]; 
} 

- (NSFetchedResultsController*)executeFetchUsingFetchedResultsControllerWithBatchSize:(NSUInteger)batchSize { 
    NSFetchedResultsController *frc = [[NSFetchedResultsController alloc] initWithFetchRequest:[self fetchRequestWithBatchSize:batchSize] managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; 
    [frc performFetch:NULL]; 
    return frc; 
} 

И немного измените существующие тесты, чтобы добавить тесты для FRC.

- (void)testThatFetchRequestWitDefaultBatchSizeFetchesEverythingEvenWithFetchedResultsController { 
    XCTAssertEqual(0, moc.registeredObjects.count); 

    NSFetchedResultsController *frc = [self executeFetchUsingFetchedResultsControllerWithBatchSize:0]; 

    XCTAssertEqual(NUM_OBJECTS, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, frc.fetchedObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, [self numberOfFaults]); 

    [[frc.fetchedObjects objectAtIndex:1] valueForKey:@"distance"]; 
    XCTAssertEqual(NUM_OBJECTS, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, frc.fetchedObjects.count); 
    XCTAssertEqual(NUM_OBJECTS-1, [self numberOfFaults]); 
} 

- (void)testThatFetchRequestWithExplicitBatchSizeOnlyFetchesTheNumberRequestedEvenWithFetchedResultsController { 
    XCTAssertEqual(0, moc.registeredObjects.count); 

    NSUInteger const BATCH_SIZE = 20; 
    NSFetchedResultsController *frc = [self executeFetchUsingFetchedResultsControllerWithBatchSize:20]; 
    XCTAssertEqual(moc, frc.managedObjectContext); 

    XCTAssertEqual(0, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, frc.fetchedObjects.count); 
    XCTAssertEqual(0, [self numberOfFaults]); 

    [[frc.fetchedObjects objectAtIndex:1] valueForKey:@"distance"]; 
    XCTAssertEqual(BATCH_SIZE, moc.registeredObjects.count); 
    XCTAssertEqual(NUM_OBJECTS, frc.fetchedObjects.count); 
    XCTAssertEqual(BATCH_SIZE-1, [self numberOfFaults]); 
} 
+0

Нет, размер партии выборки не «всего 20 объектов», он извлекает ВСЕ объекты. Можете ли вы сделать тестовый проект и проверить этот размер партии? Уверен, у вас будет такая же проблема. – Serd

+0

Спасибо за ваш код! Но у меня проблема с NSFetchResultController и его NSFetchRequest, которые имеют размер партии (он извлекает все объекты – Serd

+0

Немного поздно, но я надеюсь, что это поможет кому-то там. Невозможно ответить на вопрос надежно, потому что если используется «NSManagedObjectContext» в родительском/дочернем отношении «fetchBatchSize» будет проигнорирован. Вам нужно будет создать дополнительный «NSManagedObjectContext» типа «NSMainQueueConcurrencyType» непосредственно в «NSPersistentStoreCoordinator». См. http://stackoverflow.com/a/11470560/ 4457396 для получения дополнительной информации, а также поиска для fetchBatchSize и родительского дочернего контекста. – oyalhi

0

fetchBatchSize является лишь мерой эффективности используется Core Data, чтобы убедиться, что он получает, как несколько записей за один раз, как это возможно. Честно говоря, это совершенно необязательно в 99% случаев, и, таким образом, вы можете безопасно удалить эту строку лишнего кода.

Если вы хотите ограничить выборку определенным количеством записей (аналогично параметру SQL LIMIT, часто используемому в связи с сортировкой), вы должны установить свойство fetchLimit запроса на выборку.

fetchRequest.fetchLimit = 20 
+0

Я понимаю, что я могу заменить fetchBatchSize на свойства limit/offset, но это нехорошее решение. Можете ли вы протестировать свойство fetchBatchSize? – Serd

+0

Проверить, что? в моем ответе. – Mundi

Смежные вопросы