3

Вопросы: Как я освободить память, используемую NSManagedObjectContext (я думаю), когда число записей, которые будут вставлены в Core Data непредсказуемы, так что память может эффективно использоваться?Чрезвычайно Массивный и Continuous Импорт в Core Data эффективно

Вот мой случай: У меня есть Bluetooth устройство, которое непрерывно посылать двенадцать комплектов целого на устройство IOS на каждые 0,00125 секунд (минимальный интервал, максимальный случай будет 0.002 секунд), я должен тогда магазин эти целые числа в CoreData с меткой времени.

Объекты данных и ассоциации:

enter image description here

Когда начало процесса, заголовок записи (NSManagedObject) создается в качестве ключа для извлечения партии полученных данных от устройства Bluetooth. Объект сохраняется как сильное свойство в течение всего периода приема данных и будет удаляться из свойства (возможно, установленного нуля), когда процесс завершится.

Дизайн NSManagedObjectContext:

enter image description here Все три ManagedObjectContext являются одноплодной объект, хранящийся в AppDelegate

Код для создания ManagedObjectContext перечислены ниже:

- (NSManagedObjectContext *)masterManagedObjectContext { 
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) 
    if (_masterManagedObjectContext != nil) { 
     return _masterManagedObjectContext; 
    } 
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 
    if (!coordinator) { 
     return nil; 
    } 
    _masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
    [_masterManagedObjectContext setPersistentStoreCoordinator:coordinator]; 
    [_masterManagedObjectContext setUndoManager:nil]; 
    return _masterManagedObjectContext; 
} 
-(NSManagedObjectContext*) backgroundManagedObjectContext{ 
    if(_backgroundManagedObjectContext != nil){ 
     return _backgroundManagedObjectContext; 
    } 
    _backgroundManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType]; 
    [_backgroundManagedObjectContext setUndoManager:nil]; 
    [_backgroundManagedObjectContext setParentContext:[self masterManagedObjectContext]]; 
    return _backgroundManagedObjectContext; 
} 
-(NSManagedObjectContext*) mainManagedObjectContext{ 
    if(_mainManagedObjectContext !=nil){ 
     return _mainManagedObjectContext; 
    } 
    _mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
    [_mainManagedObjectContext setUndoManager:nil]; 
    [_mainManagedObjectContext setParentContext:[self masterManagedObjectContext]]; 
    return _mainManagedObjectContext; 
} 

Импорт обрабатывается в backgroundManagedObjectContext. Заголовок создается и сохраняется с помощью код ниже:

_header = [NSEntityDescription insertNewObjectForEntityForName:@"Header" inManagedObjectContext:_backgroundManagedObjectContext]; 
_header.startTime = [NSDate date]; 
NSError *error; 
BOOL success = [_backgroundManagedObjectContext save:&error]; 

Полученные данные создаются и хранятся с помощью ниже код, когда Bluetooth устройства уволила метод:

@autoreleasepool {  
    ReceivedData* data = [NSEntityDescription insertNewObjectForEntityForName:@"ReceivedData" inManagedObjectContext:_backgroundManagedObjectContext]; 
    //Data is set here 
    [_header addFk_header_many_dataObject:data]; 
    currentCount ++; 
    if(currentCount >=1000){ 
     currentCount = 0; 
     NSError *error; 
     BOOL success = [_backgroundManagedObjectContext save:&error]; 
    } 
} 

полученные данные будут сохранены в managedObjectContext на 1000 полученных данных.

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

Код для обработки конца процесса приведена ниже:

_header.endTime = [NSDate date]; 
_header = nil; 
NSError *error; 
BOOL success = [_backgroundManagedObjectContext save:&error]; 
[_masterManagedObjectContext performBlock:^{ 
    NSError* mastererror; 
    BOOL mastersuccess = [_masterManagedObjectContext save:&mastererror]; 
}]; 

Выпуск: Как упомянуто Core Data Performance by Apple, с использованием метода сброса NSManagedObjectContext будут удалены все управляемые объекты, связанные с контекстом и " начните сначала ", как если бы вы только что создали его.

В моем понимании это означает, что я могу назвать этот метод только в конце всего процесса. Я попытался добавить функцию сброса сразу после сохранения _backgroundManagedObjectContext и _masterManagedObjectContext. Однако память остается неизменной.

Иллюстрация использования памяти Для случая данных принимается на каждые 0,002 секунды, 0.5Мб памяти увеличилась на 1000 записей сохраняется в backgroundManagedObjectContext. Таким образом, приложение будет потреблять около 150 МБ в течение 8 минут, а память увеличится до 320 МБ, когда процесс завершится в это время, и сохранит использование памяти около 220 МБ.

Вопросы: Как я освободить память, используемую NSManagedObjectContext (я думаю), когда число записей, вставленной в Core Data непредсказуемы, так что память может эффективно использоваться?

Извините за некоторые идиотские ошибки, поскольку я совершенно новый в iOS. Я попытался изо всех сил искать вокруг, прежде чем отправлять вопрос.

Ваша помощь приветствуется. спасибо.

Замечания Я пробовал вышеупомянутый случай не более 10 минут. Однако реализация должна была распространиться на случай более чем на 1 час процесса. Я до сих пор не знаю, как справиться с таким делом.

EDIT 1 изменил код для показа взаимосвязи ReceivedData и заголовка EDIT 2 обновленный код стандарта упомянутой @flexaddicted

+0

Первое, что нужно сделать, это изменить способ работы вашего фонового MOC. В вашем случае он должен быть напрямую связан с persistentStoreCoordinator, а не с родительским мастером MOC, из-за ненужного использования памяти - для вас все данные должны идти непосредственно для хранения (sqlite), и в конечном итоге пользовательский интерфейс должен быть уведомлен об изменениях и потребностях в обновлении. В вашем коде, когда вы сохраняете фоновый MOC, все изменения необходимо переместить в master MOC и выполнить сброс на фоне. MOC сбросит (возможно) уже очистку MOC, и вся память по-прежнему используется мастером MOC. Вы не писали, на каком MOC вы вызываете сброс. –

+0

Спасибо за ваш комментарий. Для первого комментария я попытался подключиться непосредственно к persistentStoreCoordinator раньше, но производительность не является удовлетворительной. Я также записал, какой MOC я назвал reset в части ** issue **. На самом деле, я сделал оба. –

+0

Вы уже пробовали в вашем 'if (currentCount> = 1000) {' проверить, после вызова 'save', чтобы вызвать сброс контекста? –

ответ

0

Просто мой совет. Может быть, у кого-то может быть другой подход.

В этом случае я бы исключил BackgroundManagedObjectContext, и я оставил бы только MasterManagedObjectContext (как родительский элемент основного). Поскольку вам нужен небольшой профиль памяти, вам следует переключиться на механизм, который позволяет вам контролировать объем памяти вашего приложения. Итак, я создал буфер, который начнет собирать принимаемые данные. Когда буфер достигнет своего предела, я переместил бы полученные данные в MasterManagedObjectContext, чтобы сохранить их в постоянном хранилище. Здесь предел буфера (вектор структур или массив объектов в моем сознании) должен быть настроен на производительность приложения. Таким образом, у вас есть прямой контроль над создаваемыми объектами. Таким образом, вы можете выбросить их, когда вы закончите кучу импортированных данных (где связка является пределом этого вектора/массива).

В противном случае вы можете попробовать следующий подход.

@autoreleasepool {  

    NSMutableArray *temporary = [NSMutableArray array]; 

    ReceivedData* data = [NSEntityDescription insertNewObjectForEntityForName:@"ReceivedData" inManagedObjectContext:_backgroundManagedObjectContext]; 
    // Data is set here 

    // Let temporary to hold a reference of the data object 
    [temporary addObject:data]; 
    currentCount ++; 
    if(currentCount >=1000){ 
     currentCount = 0; 
     NSError *error; 
     BOOL success = [_backgroundManagedObjectContext save:&error]; 

     for(NSManagedObject *object in temporary) { 
      [_backgroundManagedObjectContext refreshObject:object mergeChanges:NO]; 
     } 
     [temporary removeAllObjects]; 
    } 
} 

Update 1

Вы можете также показать, где вы установили связь между ReceiveData и Header? Я спрашиваю об этом, потому что вы можете изменить время, когда вы установили связь между этим двумя объектами.

На основе вашего измененного кода.

@autoreleasepool {  
    receivedData* data = [NSEntityDescription insertNewObjectForEntityForName:@"ReceivedData" inManagedObjectContext:_backgroundManagedObjectContext]; 
    //Data is set here 

    [_header addFk_header_many_dataObject:data]; 
    currentCount ++; 
    if(currentCount >=1000){ 
     currentCount = 0; 
     NSError *error; 
     BOOL success = [_backgroundManagedObjectContext save:&error]; 
    } 
} 

Если вы способны posticipate этой ассоциации на мастер очереди (я думаю, вы должны установить атрибут как опциональный), вы можете сделать, как в следующем:

@autoreleasepool {  
    ReceivedData* data = [NSEntityDescription insertNewObjectForEntityForName:@"ReceivedData" inManagedObjectContext:_backgroundManagedObjectContext]; 
    // Data is set here 

    // Move it later 
    //[_header addFk_header_many_dataObject:data]; 

    currentCount ++; 
    if(currentCount >=1000){ 
     currentCount = 0; 
     NSError *error; 
     BOOL success = [_backgroundManagedObjectContext save:&error]; 
     [_backgroundManagedObjectContext reset]; 
    } 
} 

P.S. receiveData *data = ... должно быть ReceiveData *data = .... Другими словами, классы должны начинаться с заглавной буквы.

+0

Спасибо, ваш подход кажется тем же самым с @ thom-ek. Мне нужно когда-нибудь попробовать этот подход. –

+0

Спасибо за ваше обновление. Я ищу метод, который позволяет мне отложить настройку отношений в Интернете. –

+0

После некоторого поиска я могу интерпретировать * участвовать в этой ассоциации в главной очереди * как создать два независимых объекта во время процесса и установить связь, когда процесс завершается? –

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