Why this UIImage can't release - ios

I wanna save an image To sandBox... My app often crash and give MemoryWarning when I have saved many images.....
this is the code:
-(void)saveCurrentLine:(NSDictionary*)lineInfo
{
UIImage* saveImage=[lineInfo objectForKey:#"saveImage"];
NSString* savePath=[lineInfo objectForKey:#"SPN"];
NSLog(#"The savePath is :%#",savePath);
NSString* docs=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *pngPath = [docs stringByAppendingPathComponent:[NSString stringWithFormat:#"%#/%#",noteBookName,savePath]];
NSLog(#"%#",pngPath);
[UIImagePNGRepresentation(saveImage) writeToFile:pngPath atomically:YES];
UIImage* saveJPG=[lineInfo objectForKey:#"saveImage"];
UIImage* saveJIV=[UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#IV",pngPath]];
NSString *pngPathS = [docs stringByAppendingPathComponent:[NSString stringWithFormat:#"%#Scan/%#",noteBookName,savePath]];
[UIImageJPEGRepresentation([self addImage:[self scaleToSize:saveJIV size:CGSizeMake(256, 192)] toImage:[self scaleToSize:saveJPG size:CGSizeMake(256, 192)]], 1.0) writeToFile:pngPathS atomically:NO];
NSLog(#"line save over and [saveJPG count] is %d [saveJIV count] is %d [lineInfo count] is %d",[saveJPG retainCount],[saveJIV retainCount],[lineInfo retainCount]);
}
I found that the saveJPG and saveJIV does not release and I can't release them ....How can I let them release????
All method for this function:
-(void)ChangeCanvasTo:(NSNotification*)CanvasInfo
{
self.layer.opacity=1.0;
savePageName=[NSString stringWithFormat:#"%#",PageName];
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *saveImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSDictionary *currentLine=[[NSDictionary alloc] initWithObjectsAndKeys:saveImage,#"saveImage",savePageName,#"SPN",nil];
[NSThread detachNewThreadSelector:#selector(saveCurrentLine:) toTarget:self withObject:currentLine];
NSString *pngPath=[[CanvasInfo userInfo] objectForKey:#"PageName"];
PageName=pngPath;
NSLog(#"will change to %#",PageName);
NSString* docs=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
UIImage *resumeCanvas=[[UIImage alloc] initWithContentsOfFile:[docs stringByAppendingPathComponent:[NSString stringWithFormat:#"%#/%#",noteBookName,PageName]]];
drawStep=RELOAD;
curImage=resumeCanvas;
[curImage retain];
[self setNeedsDisplay];
[resumeCanvas release];
[currentLine release];
}
-(void)saveCurrentLine:(NSDictionary*)lineInfo
{
UIImage* saveImage=[lineInfo objectForKey:#"saveImage"];
NSString* savePath=[lineInfo objectForKey:#"SPN"];
NSLog(#"The savePath is :%#",savePath);
NSString* docs=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
NSString *pngPath = [docs stringByAppendingPathComponent:[NSString stringWithFormat:#"%#/%#",noteBookName,savePath]];
NSLog(#"%#",pngPath);
[UIImagePNGRepresentation(saveImage) writeToFile:pngPath atomically:YES];
UIImage* saveJPG=[lineInfo objectForKey:#"saveImage"];
UIImage* saveJIV=[UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#IV",pngPath]];
NSString *pngPathS = [docs stringByAppendingPathComponent:[NSString stringWithFormat:#"%#Scan/%#",noteBookName,savePath]];
[UIImageJPEGRepresentation([self addImage:[self scaleToSize:saveJIV size:CGSizeMake(256, 192)] toImage:[self scaleToSize:saveJPG size:CGSizeMake(256, 192)]], 1.0) writeToFile:pngPathS atomically:NO];
NSLog(#"line save over and [saveJPG count] is %d [saveJIV count] is %d [lineInfo count] is %d",[saveJPG retainCount],[saveJIV retainCount],[lineInfo retainCount]);
}

The way ARC works is in adding "release" messages automatically when it understands the object is not used any more. What you can try is adding saveJPG = nil; saveJIV=nil; at the end of yor method.
That way ARC will realize it is allowed to release them since they're not used anymore.

Related

Labels of UITableViewCells loading very slowly

As part of syncing phone to server, the phone takes data from API to populate tableview. Local placeholder images appear immediately and are replaced with remote images asynchronously. The problem is that the label for each row does not appear for up to twenty seconds until after the images have all downloaded even the label is a constant. How can I get labels to load more quickly?
-(void)configureCell:(IDItemCell *)cell withItem:(Items *)item {
[cell layoutIfNeeded];
//Label
cell.nameLabel.text = #"TEST LABEL";//does not load for 20 seconds
//image
NSString *picname = item.pic== nil ? #"" : item.pic;
cell.iconView.image = [UIImage imageNamed:#"placeholder.png"];//loads instantly
//remote fetch
if (item.pic !=nil) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithString: picname] ];
if ([[NSFileManager defaultManager] fileExistsAtPath:path])
{
cell.iconView.image =[self loadImageNamed:picname];
}
else {
NSString *picURL = [NSString stringWithFormat:#"https://www.~/pics/%#",picname];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:picURL]];
if (imgData) {
UIImage *imageFromWeb = [UIImage imageWithData:imgData];
if (imageFromWeb) {
[self saveImage:imageFromWeb asPicName:picname];
dispatch_async(dispatch_get_main_queue(), ^{
cell.iconView.image = imageFromWeb;
[cell setNeedsDisplay];
});
}
}
});
}
}
// Rounding the image view
cell.iconView.layer.cornerRadius = cell.iconView.frame.size.width / 2;
cell.iconView.clipsToBounds = YES;
cell.iconView.contentMode = UIViewContentModeScaleAspectFill;
}

Due to heavy images stored in document directory app is receiving memory warning. And app get crashed

I am working on a app which is highly dependent on saving images in document directory and retrieving it and displaying it on screen.
As soon as I display 5 -6 images in collection view the ap gets slowed up and suddenly receives memory warning and stopes functioning and app crashes.
I am using following code to display data
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
DocumentCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"DocumentCollectionViewCell"
forIndexPath:indexPath];
if(cell!=nil){
cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"DocumentCollectionViewCell" forIndexPath:indexPath];
}
Documents *documents = [arrTableData objectAtIndex:indexPath.row];
cell.imgView.contentMode = UIViewContentModeScaleAspectFit;
cell.imgContentView.layer.cornerRadius = 4.0f;
cell.imgContentView.layer.masksToBounds = YES;
cell.imgContentView.layer.borderColor = [UIColor lightGrayColor].CGColor;
cell.imgContentView.layer.borderWidth = .4f;
[cell.btnLockOrUnlock addTarget:self action:#selector(lockAction:) forControlEvents:UIControlEventTouchUpInside];
cell.btnLockOrUnlock.tag = indexPath.row;
// set count
cell.lblCount.text =[NSString stringWithFormat:#"%# Page",documents.imageCount];
cell.imgView.layer.cornerRadius = 6.0f;
cell.imgView.layer.masksToBounds = YES;
newDocDate = documents.issueDate;
// set image
NSString * passcode = documents.passcode;
if(passcode.length>3){
cell.bluredView.hidden = NO;
[cell.btnLockOrUnlock setImage:[UIImage imageNamed:#"lockWhite"] forState:UIControlStateNormal];
}
else{
[cell.btnLockOrUnlock setImage:[UIImage imageNamed:#"unlockWhite"] forState:UIControlStateNormal];
cell.bluredView.hidden = YES;
}
[cell.btnSelect addTarget:self action:#selector(cellSelectAction:) forControlEvents:UIControlEventTouchUpInside];
cell.btnSelect.tag = indexPath.row;
NSString *title = documents.title;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Fetch path for document directory
NSString * docDirectoryPath = (NSMutableString *)[documentsDirectory stringByAppendingPathComponent:title];
//-----------------path of document ------------------
NSString *filePath = [docDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"image%d.png",0]];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
int i =0;
while (!fileExists) {
filePath = [docDirectoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"image%d.png",i]];
fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
i++;
}
CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:filePath], NULL);
// Create thumbnail options
CFDictionaryRef options = (__bridge CFDictionaryRef) #{
(id) kCGImageSourceCreateThumbnailWithTransform : #YES,
(id) kCGImageSourceCreateThumbnailFromImageAlways : #YES,
(id) kCGImageSourceThumbnailMaxPixelSize : #(cell.imgView.frame.size.height)
};
// Generate the thumbnail
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
UIImage* uiImage = [[UIImage alloc] initWithCGImage:thumbnail]; //<--CRASH
cell.DocName.text = documents.docName;
//-----------------display image on cell------------------
cell.imgView.image = uiImage;
uiImage = nil;
uiImage = NULL;
documents = nil;
documents = nil;
title = nil;
thumbnail = nil;
src = nil;
options = nil;
filePath = nil;
paths = nil;
documentsDirectory = nil;
docDirectoryPath = nil;
return cell;
}
I am setting all the objects to nil.
I am using following code to save images
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Fetch path for document directory
folderName = (NSMutableString *)[documentsDirectory stringByAppendingPathComponent:folderName];
NSData *pngData = UIImagePNGRepresentation(arrImages[i]);
NSString *filePath = [folderName stringByAppendingPathComponent:[NSString stringWithFormat:#"image%d.png",i]]; //Add the file name
[pngData writeToFile:filePath atomically:YES]; //Write the file
I save the original image from camera without any compression or resizing in document directory.
I am unable to understand the problem please help.
Thanks in advance.
It seems to be due to memory leaks, check your app using instruments and lacks tool.
CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:filePath], NULL);
// Create thumbnail options
CFDictionaryRef options = (__bridge CFDictionaryRef) #{
(id) kCGImageSourceCreateThumbnailWithTransform : #YES,
(id) kCGImageSourceCreateThumbnailFromImageAlways : #YES,
(id) kCGImageSourceThumbnailMaxPixelSize : #(cell.imgView.frame.size.height)
};
// Generate the thumbnail
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
UIImage* uiImage = [[UIImage alloc] initWithCGImage:thumbnail]; //<--CRASH
CFFoundation objects follow similar memory management rules (If you create or copy you need to release it) of Obj-C before ARC (ARC doesn't manage core foundation objects).
In the code you have shown I see that you aren't releasing the CGImageRef and the CGImageSourceRef, this create two leaks and probably the crash.
Collection view cells are recycled thus the number of image opened in memory are basically the number of cells you are seeing on screen they should be the cause of your crash.

iOS 8 Crash - renderInContext:UIGraphicsGetCurrentContext()

Before iOS 8, I didn't have problems with this & now, yes.
LOG:
Assertion failed: (CGFloatIsValid(x) && CGFloatIsValid(y)), function void CGPathMoveToPoint(CGMutablePathRef, const CGAffineTransform *, CGFloat, CGFloat), file Paths/CGPath.cc, line 254.
This is my code:
UIImage* image = nil;
CGSize imageSize = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height);
UIGraphicsBeginImageContextWithOptions(imageSize, NO , 0.0f);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()]; // <- ERROR
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
My purpose is to convert the view to image.
Check for empty rectangles in what you're drawing, whether the view's bounds or the layer's content rectangle. I have noticed that assertion failure on iOS 8 where, before, empty rectangles were silently ignored.
I've added a number of...
if (!CGRectIsEmpty(bounds)) {
}
...conditions in my drawing.
We ran into this problem as well and tracked it down to a view that had a cornerRadius set on the CALayer, but had a zero size. In our case, this was only occurring on a device - not on the simulator. If you see _renderBorderInContext and CA_CGContextAddRoundRect in your backtrace then you're probably seeing the same thing.
A zero size in either dimension (height/width) will cause this error to occur if a corner radius is set. Unfortunately since it's an assertion it's not possible to catch the error and recover, so we're exploring the option of traversing the hierarchy prior to snapshotting to detect the case and recover by setting the cornerRadius to 0 and back after the call to renderInContext.
Works in IOS 8
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
fileName = [docDir stringByAppendingPathComponent:[NSString stringWithFormat:#"reporte.png"]];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
NSError *error = NULL;
BOOL written =[imageData writeToFile:fileName atomically:YES];
if (!written)
NSLog(#"write failed, error=%#", error);
else{
[self sendPorCorreo];
}
While... I will solve the export of other way.
Regards.
- (IBAction)ibaExportar:(id)sender {
NSString *mystr = #"";
NSString *csvstr;
csvstr = [NSString stringWithFormat:#",Cliente,Domicilio,DueƱo"];
mystr = [NSString stringWithFormat:#"%#,%#,%#\n",self.numCliente,self.iboDomicilio.text,self.iboDueno.text];
csvstr = [NSString stringWithFormat:#"%#\n%#",csvstr,mystr];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];
fileName = [docDir stringByAppendingPathComponent:[NSString stringWithFormat:#"Reporte.csv"]];
NSError *error = NULL;
BOOL written = [csvstr writeToFile:fileName atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!written)
NSLog(#"write failed, error=%#", error);
else{
[self sendEmail];
}
}
- (void) sendEmail {
NSString*subject;
subject= [#"Reporte Cliente " stringByAppendingString:#""];
MFMailComposeViewController *picker = [[MFMailComposeViewController alloc] init];
picker.mailComposeDelegate = self;
[picker setSubject:subject];
NSData *dataFile = [NSData dataWithContentsOfFile:fileName];
[picker addAttachmentData:dataFile mimeType:#"text/csv" fileName:#"Reporte.csv"];
NSString *emailBody =subject;
[picker setMessageBody:emailBody isHTML:NO];
[self presentViewController:picker animated:YES completion:nil];
}
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[self dismissViewControllerAnimated:YES completion:nil];
}
Check your float with isnan(x) before using with Core Graphics.
According to the answer from tyler, I fix the problem. You can just find out the problematic view in self.view. The ios 8 not allow the zero size view to set the cornerRadius. So you must have a zero size view and set the cornerRadius for it. You can run the following code to find it out and fix it.
- (void)findZeroSizeControlWithSuperView:(UIView *)superView {
[self isProblematicCrotrol:superView];
[superView.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[self isProblematicCrotrol:obj];
}];
}
- (BOOL)isProblematicCrotrol:(UIView *)view {
if ((view.frame.size.width == 0 || view.frame.size.height == 0) && view.layer.cornerRadius != 0) {
NSLog(#"this is the problematic view:%#", view);
return YES;
} else {
return NO;
}
}

Using iCarousel with images in folder

I have a folder (Documents/Images) which I use to store images downloaded from online, when the view with iCarsousel is launched infomation on which images to use is also sent so only certain images from the folder will be used.
However for some reason the below code does not seem to work and a blank view is shown and no error message given.
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
[carousel setType:iCarouselTypeCylinder];
[self getImages];
return [images count];
}
- (void)getImages{
images=[[NSMutableArray alloc]init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:databaseName];
db = [FMDatabase databaseWithPath:writableDBPath];
if (![db open]) {
return;
}
NSLog(#"getting images");
NSLog(_galleryid);
FMResultSet *result = [db executeQuery:#"SELECT * FROM mediaImages WHERE galleryID = ?;", _galleryid];
while ([result next]){
NSString *filename = [result stringForColumnIndex:1];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSFileManager *fileManager = [NSFileManager defaultManager];
//configure carousel
NSString *fPath = [documentsDirectory stringByAppendingPathComponent:#"Images"];
NSString *filepath = [fPath stringByAppendingString:#"/"];
filepath = [filepath stringByAppendingString:filename];
NSLog(filepath);
[images addObject:filepath];
}
}
- (UIView *)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(UIView *)view
{
view = [[UIView alloc] init];
view.contentMode = UIViewContentModeScaleAspectFit;
CGRect rec = view.frame;
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
rec.size.width = 250;
rec.size.height = 250;
}
view.frame = rec;
UIImageView *iv;
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
iv=[[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 200, 200)];
}
NSString *temp=[images objectAtIndex:index];
iv.image=[UIImage imageNamed:temp];
iv.contentMode = UIViewContentModeScaleAspectFit;
[view addSubview:iv];
return view;
}
- (void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index
{
NSLog(#"Image is selected.");
}
- (CGFloat)carousel:(iCarousel *)carousel valueForOption:(iCarouselOption)option withDefault:(CGFloat)value
{
switch (option)
{
case iCarouselOptionWrap:
{
return YES;
}
default:
{
return value;
}
}
}
Is there anything visably wrong with the code, or perhaps a good way to debug what the issue is?
My guess is that the problem is here:
iv.image=[UIImage imageNamed:temp];
temp is a path to a file, not the name of an image, so this won't work. Perhaps you want to use + imageWithContentsOfFile: instead?
If that's not the only problem, I highly recommend trying to isolate it further yourself with logging or debugging; for example if you had logged the value of temp and the image you get back from imageNamed:, you probably would have seen this problem as well.

Writing/loading to/from file

Im trying to learn how to save/load images, and i just don't get why this wont work. Im writing a screenshot to the filesystem like this:
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)])
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [UIScreen mainScreen].scale);
else
UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData * data = UIImagePNGRepresentation(image);
NSArray *directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [directories objectAtIndex:0];
NSString *key = [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
[data writeToFile:key atomically:YES];
And in the "init" medthod in my UITableView subclass, i do this:
pics = [[NSMutableDictionary alloc]initWithContentsOfFile:[self dataFilePath]];
dataFilePath method:
- (NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:#"screenshots.archive"];
}
To test if this works i have this delegate method:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return pics.count;
}
I test it by taking a screenshot, and then initializing my UITableview subclass, but it show no rows. What am i doing wrong?
There are a few key issues with the code that are causing it to not work. You're storing the image data directly to the file and trying to read it back as a dictionary. You'll want to wrap the image in an array first, and write the array to the file. Then you'll want to read the file into an array for the table to display. To sum up the changes:
Change
[data writeToFile:key atomically:YES];
to
NSMutableArray *storageArray = [NSMutableArray arrayWithContentsOfFile:key];
if(!storageArray)
storageArray = [NSMutableArray arrayWithObject:data];
else
[storageArray addObject:data];
[storageArray writeToFile:key atomically:YES];
and change
pics = [[NSMutableDictionary alloc]initWithContentsOfFile:[self dataFilePath]];
to
pics = [[NSArray alloc] initWithContentsOfFile:[self dataFilePath]];

Resources