Я открываю камеру с UIImagePickerControllerSourceTypeCamera
и обычным cameraOverlayView
, поэтому я могу сделать несколько фотографий без шага «Использовать фотографию».UIGraphicsGetImageFromCurrentImageContext() - Утечка памяти
Это прекрасно работает, но в функции сохранения фотографий есть утечка памяти. Благодаря большому количеству отладки и исследований я сузил ее до функции UIGraphicsGetImageFromCurrentImageContext
.
Вот фрагмент кода, где это происходит:
UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]);
[[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
я рыскал по интернету и, кажется, что UIGraphicsGetImageFromCurrentImageContext()
функция (цитата из this SO question) «возвращает новый autoreleased UIImage
и указывает finalTimestampImage
Ивар к нему ранее выделенному UIImage
никогда не было выпущено, переменная к нему просто переадресована в другое место ».
Я пробовал так много решений, которые, по-видимому работали для других:
Добавление
timestampedImage.layer.contents = nil;
послеUIGraphicsEndImageContext
CGContextRef context = UIGraphicsGetCurrentContext();
Добавление иCGContextRelease(context);
послеUIGraphicsEndImageContext
Обертывание выше фрагмент кода в
NSAutoreleasePool
Обертывание всю
saveThisPhoto
функцию вNSAutoreleasePool
Создание
NSAutoreleasePool
, когда камера всплывает и вызова[pool release]
когдаdidReceiveMemoryWarning
называетсяЗакрытие всплывающего окна камеры при
didReceiveMemoryWarning
называется, надеясь, что это будет очистить бассейнКаждая возможная комбинация из вышеперечисленных
Все, что я стараюсь, когда я фотографирую, я вижу, как Memory Utilized
поднимается и не падает, когда я многократно фотографирую на устройстве.
Кто-нибудь знает, как я могу освободить объект автореферации, созданный UIGraphicsGetImageFromCurrentImageContext
?
В качестве альтернативы, существует альтернативный способ сделать UIImage
из UIImageView
?
Edit:
Вот полные функции, как просили. Там добавлено много дополнительных выпусков, чтобы попробовать убедиться, что все очищено. Я прошел проверку и протестировал на утечку памяти с каждым блоком кода в saveThisPhoto
систематически, и это происходит только тогда, когда выполняется блок UIGraphicsGetImageFromCurrentImageContext
(фрагмент выше).
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSLog(@"SAVING PHOTO");
[self saveThisPhoto:info];
picker = nil;
[picker release];
info = nil;
[info release];
}
- (void)saveThisPhoto:(NSDictionary *)info {
// Get photo count for filename so we're not overriding photos
int photoCount = 0;
if ([[NSUserDefaults standardUserDefaults] objectForKey:@"photocount"]) {
photoCount= [[[NSUserDefaults standardUserDefaults] objectForKey:@"photocount"] intValue];
photoCount++;
}
[[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithFormat:@"%d", photoCount] forKey:@"photocount"];
[[NSUserDefaults standardUserDefaults] synchronize];
// Obtaining saving path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:@"ri_%d.jpg", photoCount];
NSString *fileNameThumb = [NSString stringWithFormat:@"ri_%d_thumb.jpg", photoCount];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:fileName];
NSString *imagePathThumb = [documentsDirectory stringByAppendingPathComponent:fileNameThumb];
// Extracting image from the picker and saving it
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
// SAVE TO IPAD AND DB
if ([mediaType isEqualToString:@"public.image"]){
// Get Image
UIImage *editedImage = [info objectForKey:UIImagePickerControllerOriginalImage];
// Figure out image orientation
CGSize resizedSize;
CGSize thumbSize;
if (editedImage.size.height > editedImage.size.width) {
resizedSize = CGSizeMake(480, 640);
thumbSize = CGSizeMake(150, 200);
} else {
resizedSize = CGSizeMake(640, 480);
thumbSize = CGSizeMake(150, 113);
}
// MAKE NORMAL SIZE IMAGE
UIImage *editedImageResized = [editedImage resizedImage:resizedSize interpolationQuality:0.8];
// clean up the one we won't use any more
editedImage = nil;
[editedImage release];
// ADD TIMESTAMP TO IMAGE
// make the view
UIImageView *timestampedImage = [[UIImageView alloc] initWithImage:editedImageResized];
CGRect thisRect = CGRectMake(editedImageResized.size.width - 510, editedImageResized.size.height - 30, 500, 20);
// clean up
editedImageResized = nil;
[editedImageResized release];
// make the label
UILabel *timeLabel = [[UILabel alloc] initWithFrame:thisRect];
timeLabel.textAlignment = UITextAlignmentRight;
timeLabel.textColor = [UIColor yellowColor];
timeLabel.backgroundColor = [UIColor clearColor];
timeLabel.font = [UIFont fontWithName:@"Arial Rounded MT Bold" size:(25.0)];
timeLabel.text = [self getTodaysDateDatabaseFormat];
[timestampedImage addSubview:timeLabel];
// clean up what we won't use any more
timeLabel = nil;
[timeLabel release];
// make UIIMage out of the imageview -- MEMORY LEAK LOOKS LIKE IT IS IN THIS BLOCK
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIGraphicsBeginImageContextWithOptions(timestampedImage.frame.size, timestampedImage.opaque, [[UIScreen mainScreen] scale]);
[[timestampedImage layer] renderInContext:UIGraphicsGetCurrentContext()];
UIImage *finalTimestampImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
timestampedImage.layer.contents = nil;
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRelease(context);
// clean up the one we won't use any more
timestampedImage = nil;
[timestampedImage release];
// SAVE NORMAL SIZE IMAGE TO DOCUMENTS FOLDER
NSData *webDataResized = UIImageJPEGRepresentation(finalTimestampImage, 1.0); // JPG
[webDataResized writeToFile:imagePath atomically:YES];
// clean up the one we won't use any more
finalTimestampImage = nil;
[finalTimestampImage release];
[pool release]; // to get rid of the context image that is stored
// SAVE TO DATABASE
[sqlite executeNonQuery:@"INSERT INTO inspection_images (agentid,groupid,inspectionid,areaid,filename,filenamethumb,filepath,orderid,type) VALUES (?, ?, ?, ?, ?, ?, ?, ?,?) ",
[NSNumber numberWithInt:loggedIn],
[NSNumber numberWithInt:loggedInGroup],
myInspectionID,
[[tableData objectAtIndex:alertDoMe] objectForKey:@"areaid"],
fileName,
fileNameThumb,
documentsDirectory,
[NSNumber numberWithInt:photoCount],
[NSNumber numberWithInt:isPCR]
];
// Clean up
webDataResized = nil;
[webDataResized release];
} else {
NSLog(@">>> IMAGE ***NOT*** SAVED");
}
NSLog(@"IMAGE SAVED - COMPLETE");
info = nil;
[info release];
}
Вы подтвердили, что проблема связана не с дальнейшим кодом, использующим изображение finalTimestampImage? Возможно, где-то есть цикл сохранения. – rmaddy
'finalTimestampImage' используется для получения' UIImageJPEGRepresentation', который сохраняется на устройстве, тогда оба из них «выпущены». Я все еще убежден, что это скрытая 'UIImage' функция' UIGraphicsGetImageFromCurrentImageContext' создает, как упоминалось в другом вопросе SO. – Batnom
Нет, вы неправильно поняли предыдущий вопрос SO. «Ранее выделенный UIImage» - это UIImage в '_renderImage = [[UIImage alloc] init];' который протекает в '_renderImage = UIGraphicsGetImageFromCurrentImageContext();'. Если вы объявите переменную, как в своем фрагменте, она не будет протекать. Возможно, вы могли бы разместить более полный образец кода. – HBu