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
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.
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);
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];
}
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;
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];
}