Должен ли NSPurgeableData многократно использоваться после удаления его содержимого?
У меня есть код, использующий NSPurgeableData
это работало, пока использование памяти моей машины не стало высоким, и в этот момент я начал получать исключение. Это сообщение в исключении:
*** Завершение работы приложения из-за невыполненного исключения "NSGenericException", причина: "*** -[Длина NSPurgeableData]: доступ осуществлен вне успешных вызовов -beginContentAccess и -endContentAccess".
Это суть моего кода:
- (NSImage *)imageProperty {
if (!self.purgeableImage || ![self.purgeableImage beginContentAccess]) {
if (!self.purgeableImage) {
self.purgeableImage = [NSPurgeableData data];
}
NSImage *image = // Get the image
// THIS LINE CAUSES THE EXCEPTION
[self.purgeableImage setData: image.TIFFRepresentation];
}
}
- (void)clearImage {
[self.purgeableImage endContentAccess];
// Putting in this line works, but shouldn't be necessary, should it?
//self.purgeableImage = nil
}
clearImage
сбалансирован с вызовами imageProperty. Я могу воспроизвести исключение с помощью этого теста:
- (void)testImageProperty_CallTwiceWithMemoryPressure {
MyClass *instance = // Initialize the sucker
NSImage *image = instance.imageProperty;
NSPurgeableData *purgeableData = image.purgeableImage;
XCTAssertNotNil(image, @"Image not loaded");
XCTAssertEqual(image.size.width, (CGFloat)988, @"Image loaded with incorrect width");
XCTAssertEqual(image.size.height, (CGFloat)1500, @"Image loaded with incorrect height");
[instance clearImage];
// Discard, as if there were memory pressure
[purgeableData discardContentIfPossible];
XCTAssertTrue(purgeableData.isContentDiscarded, @"Failed to simulate memory pressure");
// TRIGGERS THE EXCEPTION
image = instance.imageProperty;
XCTAssertNotNil(image, @"Image not loaded on second attempt");
}
Я могу устранить исключение, раскомментировав вторую строку -clearImage
, но я не думаю, что это было необходимо. Должен ли я быть в состоянии продолжать использовать NSPurgeableData
объект после того, как его исходные данные были отброшены?
Обновление: дополнительный обходной путь
Проблема с обнулением после звонка -endContentAccess
является то, что класс эффективно не обеспечивает кэширование. Другое решение, которое я нашел, это обновить ведущие if
заявления вроде так:
if (!self.purgeableImage || self.purgeableImage.isContentDiscarded || ![self.purgeableImage beginContentAccess]) {
if (!self.purgeableImage || self.purgeableImage.isContentDiscarded) {