IOS: UIImage sent to deallocated instance - ios

I have this code:
imageNumber++;
UIImage *image = [[UIImage alloc]init];
image = [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image]; //<-- here it crash
[image release];
so, after a few minuted my app crash with this message
[UIImage isKindOfClass:]: message sent to deallocated instance
why?? can you help me?

imageNumber++;
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image];
The problem with your code is that you allocate a UIImage object on image variable and then without releasing it you set it to another autoreleased object. [UIImage imageNamed:] returns an autoreleased UIImage object.

You are allocating a new image, and then you are assigning that pointer to an autoreleased UIImage returned by UIImage imageNamed:, causing a memory leak, then you try to release an autoreleased object, which get released again, causing the error.
imageNumber++;
image = [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image]; //<-- here it crash

it seems like you got it all wrong. At first you alloc-init object and then assign autorelased object to the pointer, making the first object leaking. Here is the correct code:
imageNumber++;
UIImage *image [UIImage imageNamed:[NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber]];
[imageToColor setImage:image];

1) You don't need to allocate an empty image before loading the image from a file.
2) Are you sure that the image specified by the string [NSString stringWithFormat:#"l%d_s%d.png", currentSet, imageNumber] actually exists and is available to the app ?
the imageNamed call will return null if that image cannot be found. Step through in the debugger and see if the image is actually loaded.

Related

Wait till setImageWithURL is loaded SDWebImage

What i need is to wait till setImageWithURL has finished proccesing the image, here is my code on the viewDidLoad method:
UIImageView *test = [[UIImageView alloc] init];
[test setImageWithURL:[NSURL URLWithString:object.imageUrl]];
Is there anyway to set this method to run synchronous? I have tried the completed block, but for some strange reason it never gets called.
From what I remember SDWebImage doesn't have methods to download/set image synchronously (for obvious reasons). But if your use case wants you to use a synchronous method, try this:
UIImageView *test = [[UIImageView alloc] init];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
[test setImage:image];
Hope this helps.

Getting NSData from UIImage object that contains CGImage

In order to upload an image file to my server, I need to get it's NSData. I am having trouble doing this right now, because my UIImage contains a CGImage.
Let me show you how I am doing things. When a user takes a photo, this is what I do with the captured photo:
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc]initWithData:imageData];
_subLayer = [CALayer layer];
image = [self selfieCorrection:image];
image = [self rotate:image andOrientation:image.imageOrientation];
CGRect cropRectFinal = CGRectMake(cropRect.origin.x, 140, cropRect.size.width, cropRect.size.height);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRectFinal);
_subLayer.contents = (id)[UIImage imageWithCGImage:imageRef].CGImage;
In the above code, I create a UIImage, and initialize it with the imageData object. I also create a layer object called _subLayer that will display the final image on the screen. The image's orientation is then rotated and corrected, and then I setup a CGRect to crop the part of the image I want to keep.
The most important part are the last 2 statements. I create a CGImageRef called imageRef using the original UIImage. Then, in the last statement, I set the contents property of _subLayer to equal my final image.
A little further down in this same view controller, inside of an IBAction I have the following statement which helps me pass the image to my next view controller: sendFriendsVC.finalPhotoToSend = _subLayer.contents;
finalPhotoToSend is a property that I have setup in the header file of my next view controller like this:
#property (nonatomic, retain) UIImage *finalPhotoToSend;
The data is successfully passed when I segue to the next view controller, but when I NSLog finalPhotoToSend, even though it is a UIImage, it prints as this to the console:
<CGImage 0x1563dac0>
In order to upload photos to my backend server service, it requires me to create an object using NSData. I have tried using these 2 methods to get the NSData out of the finalPhotoToSend object:
NSData *imageData = UIImageJPEGRepresentation(finalPhotoToSend, 0.7);
and
NSData *imageData = UIImagePNGRepresentation(finalPhotoToSend);
But those always give me the following error in xcode:
NSInvalidArgumentException', reason: '-[__NSCFType CGImage]: unrecognized selector sent to instance
I am not sure what to do. Is there a different method I should be using to get NSData out of my UIImage since it is technically holding a CGImage? Should I be doing something differently before I even pass the data to my next view controller?
Edit for Michael:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:self {
if ([segue.identifier isEqualToString:#"mediaCaptureToSendToFriendsSegue"]) {
SendToFriendsViewController *sendFriendsVC = segue.destinationViewController;
sendFriendsVC.finalPhotoToSend = _subLayer.contents;
}
}
I just figured it out. Here's what I ended up using for the IBAction method implementation:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:self {
if ([segue.identifier isEqualToString:#"mediaCaptureToSendToFriendsSegue"]) {
SendToFriendsViewController *sendFriendsVC = segue.destinationViewController;
UIImage* image2 = [UIImage imageWithCGImage:(__bridge CGImageRef)(_subLayer.contents)];
sendFriendsVC.finalPhotoToSend = image2;
}
}
I'm new to objective-c and not really entirely sure what the following statement is even doing:
UIImage* image2 = [UIImage imageWithCGImage:(__bridge CGImageRef)(_subLayer.contents)];
But xcode suggested it and it works. Now on the next view controller, the finalPhotoToSend object NSLogs as a UIImage instead of a CGImage.
Better answer:
You need to truly set a UIImage object (and not a CGImage pointer) to a property that you've declared to be a UIImage object.
Original:
if "finalPhotoToSend" is a property, you should be doing:
NSData *imageData = UIImageJPEGRepresentation(self.finalPhotoToSend, 0.7);
and not:
NSData *imageData = UIImageJPEGRepresentation(finalPhotoToSend, 0.7);

Received Memory Warning iOS

In my split view iPad app the default detail view loads a random image from an array and does this any time the user goes back to that view. The app loads fine with that view and I can go to another view fine. The problem is that if I go back to that view, sometimes it will crash and sometimes it will crash if I select another view after going back to the default view. I do not show any leaks when I run the leaks tool and I don't show anything in the log every time a crash occurs. I did receive a "Received Memory Warning" log once so it the crashes must have something to do with a leak somewhere, I'm just not sure where. I am using ARC. Any ideas?
Here is my viewDidLoad method:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage *agelity = [UIImage imageNamed:#"Agelity"];
UIImage *agelity2 = [UIImage imageNamed:#"Agelity2"];
UIImage *biltmore = [UIImage imageNamed:#"Biltmore"];
UIImage *biltmore2 = [UIImage imageNamed:#"Biltmore2"];
UIImage *biltmore3 = [UIImage imageNamed:#"Biltmore3"];
UIImage *choice = [UIImage imageNamed:#"Choice"];
UIImage *enterprise = [UIImage imageNamed:#"Enterprise"];
UIImage *enterprise2 = [UIImage imageNamed:#"Enterprise2"];
UIImage *grainger = [UIImage imageNamed:#"Grainger"];
UIImage *grainger2 = [UIImage imageNamed:#"Grainger2"];
UIImage *greatWolf = [UIImage imageNamed:#"Great_Wolf"];
UIImage *greatWolf2 = [UIImage imageNamed:#"Great_Wolf2"];
UIImage *officeDepot = [UIImage imageNamed:#"Office_Depot1"];
UIImage *officeDepot2 = [UIImage imageNamed:#"Office_Depot2"];
UIImage *officeDepot3 = [UIImage imageNamed:#"Office_Depot3"];
UIImage *sams = [UIImage imageNamed:#"Sams"];
UIImage *sams2 = [UIImage imageNamed:#"Sams2"];
NSMutableArray *benefitAds = [[NSMutableArray alloc]initWithObjects:agelity, agelity2, biltmore, biltmore2, biltmore3, choice, enterprise, enterprise2, grainger, grainger2, greatWolf, greatWolf2, officeDepot, officeDepot2, officeDepot3, sams, sams2, nil];
int randomIndex = arc4random() % [benefitAds count];
adImage.image = [benefitAds objectAtIndex:randomIndex];
[self configureView];
}
EDIT: I am trying to use the suggestion of using imageWithData instead of imageNamed so I'm doing this:
NSData *agelityData = [NSData dataWithContentsOfFile:#"Agelity"];
UIImage *agelity = [UIImage imageWithData:agelityData];
but now the app crashes at launch with on the line:
int randomIndex = arc4random() % [benefitAds count];
with:
Thread 1: EXC_ARITHMETIC(code=EXC_I386_DIV, subcode=0x0)
When I run it on my device instead of the simulator, I get this:
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 3051310543 beyond bounds for empty array'
EDIT: I set an exception breakpoint because I'm getting an exc_bad_access code=1 error. It looks like the app randomly crashes at times when I'm changing the detail view. I guess I'll create a new question.
Thanks for all the help!
I don't know if it is exactly this that is causing the crash (high chances that it might be), but I really suggest you to don't store all images inside your array.
A better approach would be store the name of the images, and the allocate just one UIImage, with the name selected.
See this:
- (void)viewDidLoad
{
NSMutableArray *benefitAds = [[NSMutableArray alloc]initWithObjects:#"Agelity", #"Agelity2", #"Biltmore", #"Biltmore2", #"Biltmore3", #"Choice", #"Enterprise", #"Enterprise2", #"Grainger", #"Grainger2", #"Great_Wolf", #"Great_Wolf2", #"Office_Depot1", #"Office_Depot2", #"Office_Depot3", #"Sams", #"Sams2", nil];
int randomIndex = arc4random() % [benefitAds count];
if(randomIndex < [benefitAds count]) {
adImage.image = [UIImage imageNamed:[benefitAds objectAtIndex:randomIndex]];
[self configureView];
}
else
{
//error message
}
}
Please give some feedback it worked or not.
EDIT:
Try to check if the random number get is really a valid index before using it.
imageNamed: uses the internal cache which does not empty itself on memory warnings. Try imageWithData
- (void)didReceiveMemoryWarning {
if([self isViewLoaded] && self.view.window == nil) {
self.view = nil;
}
[super didReceiveMemoryWarning];
}

How to fix the Core Foundation object with a +1 retain count (ARC)?

Here is my method:
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(aSampleBuffer);
CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer];
CIContext *context = [CIContext contextWithOptions:nil];
CGImageRef myImage = [context
createCGImage:ciImage
fromRect:CGRectMake(0, 0,
CVPixelBufferGetWidth(imageBuffer),
CVPixelBufferGetHeight(imageBuffer))];
return [UIImage imageWithCGImage:myImage];
But last line show me is Potential leak of an object stored into 'myimage', and the line of myImage is Method returns a Core Foundation object with a +1 retain count. But my application is ARC enabled, so I can't release something. How can I fix it? Thanks.
My application is ARC enabled, so I can't release something
Wrong. ARC prevents you from sending the release message to Objective-C objects, since it manages their memory for you.
However you still have to manually manage the memory in any other case (i.e. C structures). You can - and must - use retain/release functions on such structures whenever appropriate.
In this case you have to manually call CGImageRelease on myImage, balancing the retain count, by doing (as proposed by H2CO3)
UIImage *retVal = [UIImage imageWithCGImage:myImage];
CGImageRelease(myImage);
return retVal;
UIImage *retVal = [UIImage imageWithCGImage:myImage];
CGImageRelease(myImage);
return retVal;

Memory Leak iOS (UIImageView,UIImage,CGImage) not freed on ARC

Im trying to implement a simple video stream but for some reason my memory won't get freed:
(void)updateImage:(UIImage *)image{
self.indicator.hidden = TRUE;
//CGImageRelease([self.imageView.image CGImage]);
self.imageView.image = nil;
self.imageView.image = image;
[self.imageView setNeedsDisplay];
}
If I use
CGImageRelease([self.imageView.image CGImage]);
memory will be freed. But when I return to a previous view controller the app will crash as it tries to free the allocated memory for that image, which I already freed. This method is called from a async task which creates an image using:
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGDataProviderRelease(provider);
CFRelease(data);
As I understood it the UIImage now owns the CGImage and I shouldn't have to release it.
So is there anyway to ensure that the UIImage is freed when I updated the UIImageView with a new image?
Ok so I finally figured out the problem.
As I said I was using some background thread to perform the image update, the solution was to add it as a autorelease pool as following:
#autoreleasepool {
[self.delegate performSelectorOnMainThread:#selector(updateImage:) withObject:[self fetchImage] waitUntilDone:NO];
}

Resources