xcode gdb pauses on ipad device - ipad

I'm try to create some images and store it inside the Documents folder. When I run it on the simulator it is fine. However when I run it through the ipad device, the gdb just pauses at a certain point and doesn't give me much information to work with. I used the analyser to check what items to release to check memory leaks. Im running 4.3 SDK.
I'm not sure what the actual issue is. Sometimes looping through 100 images and storing them is ok but then after a while it just pauses. Where can I look further for debug or clues on how to fix this. I have provided some code.
for(int i = 0; i < totalpages; i++)
{
NSString *imagePath = [NSString stringWithFormat:#"%#/%d.jpg",
imageFullPathFolder, i+1];
if(![manager fileExistsAtPath:imagePath])
{
NSString *urlParams = [NSString stringWithFormat:#"SOMEURL",
fileSourceId, i+1];
NSURL *imageUrl = [NSURL URLWithString:urlParams];
UIImage *image = [UIImage imageWithData:[NSData
dataWithContentsOfURL:imageUrl]];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
[manager createFileAtPath:imagePath contents:imageData
attributes:nil];
[imageData release];
}
}

You don't need to release the image data returned by UIImageJPEGRepresentation (you don't own it; you're over-releasing it).

Related

UIImage failed to be loaded for IOS 7.x SPECIFIC

I was trying to load image using method:
[UIImage imageNamed:imageName]
[UIImage imageWithContentsOfFile:imagePath]
In IOS 8.x, the images are loaded. However in IOS 7.x simulators, the above methods always return nil. This situation happened in both simulators and devices.
NSBundle *myBundle = [NSBundle findMyBundle];
[myBundle load];
NSString *imagePath = [NSString stringWithFormat:#"%#/%#", [myBundle bundlePath], imageName];
UIImage *targetImage = [UIImage imageWithContentsOfFile:imagePath];
NSLog(#"FrameworkBundle: %#", myBundle);
// Bundle does exist For IOS 7.x
NSLog(#"Image: %#", targetImage);
// targetImage = nil for IOS 7.x; while it does return image for IOS 8.x
Is there any method need to notice for loading UIImage about IOS 7.x devices / simulators.?
Edit:
Here is what worked out for me:
// I have to specify imageType to be #"png"
// If one compose the path without the fileType ending, it does not load the image properly.
NSString *imagePath = [myBundle pathForResource:imageName ofType:#"png"];
UIImage *myImage = [UIImage imageWithContentsOfFile:imagePath];
I think there was a change when iOS 8 launched in how and where the bundles exist, I just search on Stackoverflow and probably this question (and its answer can help you), you probably have to use a different loading method for locating bundle or resource
ios 8: Bundle path changes
PS:should have been a comment in your answer but dont have enought reputation at the moment :)

Memory management in iOS , Simulator vs idevice gives different result

i am downloading images from a server, this is my code.
-(void) DownloadImages
{
NSLog(#"Images count to download %lu",(unsigned long)[productID count]); // about 3000
if ([productID count] > 0)
{
// Document Directory
NSString *myDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
for (i = 0; i < [productID count]; i++)
{
#autoreleasepool // is this right of use autoreleasepool???
{
#autoreleasepool
{
[self performSelectorInBackground:#selector(UpdateUI) withObject:nil];
}
NSLog(#"image no %d", i);
NSString *imageURL = [NSString stringWithFormat:#"http://serverPath/%#/OnlineSale/images/products/%#img.jpg",clientSite,[productID objectAtIndex:i]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
// Reference path
NSString *imagePath = [NSString stringWithFormat:#"%#/%#img.jpg",myDirectory,[productID objectAtIndex:i]];
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
[imageData writeToFile:imagePath atomically:YES];
}
}
NSLog(#"Downloading images completed...");
}
}
EDIT: this is UpdateUI method
-(void) UpdateUI
{
spinner.hidden = NO;
[spinner startAnimating];
progressCounter.hidden = NO;
status.text = #"Synchronising Product Images...";
progressCounter.text = [NSString stringWithFormat:#"%d / %lu", i,(unsigned long)[productID count]];
}
while processing this, when i am in simulator the maximum memory used is:
on more than 1500 images download.
but testing on iPad, the maximum memory is reached to 106.9 MB and app crashed with this message, just after 500 images download:
and screen shows this message:
i am stuck on this point from last two days, after scratching my head don't find any solution. please help me on this issue..
Edit:
using autoreleasedpool way is right or not???
First of all, I would suggest enclosing the whole for loop block inside of #autoreleasepool. It would look like this:
for (i = 0; i < [productID count]; i++)
{
#autoreleasepool // is this right of use autoreleasepool???
{
[self performSelectorInBackground:#selector(UpdateUI) withObject:nil];
NSLog(#"image no %d", i);
NSString *imageURL = [NSString stringWithFormat:#"http://serverPath/%#/OnlineSale/images/products/%#img.jpg",clientSite,[productID objectAtIndex:i]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
// Reference path
NSString *imagePath = [NSString stringWithFormat:#"%#/%#img.jpg",myDirectory,[productID objectAtIndex:i]];
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
[imageData writeToFile:imagePath atomically:YES];
}
}
If what you tried to accomplish with your #autoreleasepool block was handling memory allocated in updateUI, that is not the right approach. You should instead enclose updateUI body inside of #autoreleasepool.
I would also suggest to post the content of updateUI; you could even comment that call out and see whether the download-only is causing the memory issue.
More generally, it seems pretty suspicious to me that you are updating the UI on a background thread. UI should be only updated on the main thread, as a general practice. (But without seeing updateUI definition, I cannot really say if this is ok or not).
About the different results you get with a device or the simulator, this is "normal". The simulator is totally unreliable when it come to memory handling, you could also detect leaks with the simulator that are not there on a device.
EDIT:
As an easy patch, try with this approach:
for (i = 0; i < [productID count]; i++)
{
dispatch_async(dispatch_get_main_queue(), ^{
[self UpdateUI];
NSLog(#"image no %d", i);
NSString *imageURL = [NSString stringWithFormat:#"http://serverPath/%#/OnlineSale/images/products/%#img.jpg",clientSite,[productID objectAtIndex:i]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]];
// Reference path
NSString *imagePath = [NSString stringWithFormat:#"%#/%#img.jpg",myDirectory,[productID objectAtIndex:i]];
NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(image, 1.0f)];
[imageData writeToFile:imagePath atomically:YES];
});
}
As you'll notice, I am dispatching each step in the loop individually. In this way, the mail loop will be able to update the UI. Notice that this implementation is not optimal, since dataWithContentsOfURL will take a little to execute (since it entails a network access) and should not be executed on the main thread (but you were doing it already like this). That should be dispatched on a background queue.
You should use more appropriate method for fetching Image data.
I suggest you to try NSURLDownload class.
Alternatively you could use one of popular 3rd party networking framework like AFNetworking

Memory pressure downloading many images

I am trying to download thousands of pictures (Maximum 350 Kb each) from the server, but I go by over a thousand images I receive the alert "Memory Presure".
Basically I have an array with all the names of the images and do a loop to bring one to one like this:
for (int x=0; x<unique.count; x++) {
NSURL *ImageLink = [NSURL URLWithString:[NSString stringWithFormat:#"http://urltoimagesfolder.com/", [unique objectAtIndex:x]]];
NSData *data = [NSData dataWithContentsOfURL:ImageLink];
UIImage *img = [[UIImage alloc] initWithData:data];
if (data.length !=0) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[unique objectAtIndex:x]]; //add our image to the path
[UIImageJPEGRepresentation(img, 1.0) writeToFile:fullPath atomically:YES];
//[self saveImage:img :NombreFoto];
//[self Miniatura:img :[NSString stringWithFormat:#"mini-%#", [unique objectAtIndex:x]]];
}
data = nil;
img = nil;
}
Question: How I can download all the images without the app crash with memory pressure?
UIImageJPEGRepresentation() may cause the memory overflow.
But you don't need to use that function, you can check if the received data is image and write its bytes directly to disk via sending message writeToFile: to data object.
You can fix you code like this:
for (int x=0; x<unique.count; x++) {
NSURL *ImageLink = [NSURL URLWithString:[NSString stringWithFormat:#"http://urltoimagesfolder.com/", [unique objectAtIndex:x]]];
NSData *data = [NSData dataWithContentsOfURL:ImageLink];
if (data.length !=0) {
UIImage *img = [[UIImage alloc] initWithData:data];
if (img) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:[unique objectAtIndex:x]]; //add our image to the path
[data writeToFile:fullPath atomically:YES];
}
img = nil;
}
data = nil;
}
However this is not the optimal solution. -dataWithContentsOfURL: is synchronous method and will stop execution of your main thread while downloading the file. As a consequence the UI will hang during the download. To make your UI not to hang you can use asynchronous url requests.
See -sendAsynchronousRequest:queue:completionHandler: method of the NSURLConnection class. Or if your app is only for iOS 7 see -dataTaskWithURL:completionHandler: as alternative.

iPhone app flipbook animation crashing on device

The app uses a series of jpg's and a timer that steps through them to make an animation.
During the animation on the device, it crashes (didReceiveMemoryWarningError.)
I'm new to iPhone programming and Objective-C. How can I optimize this flipbook for the iPhone?
I can imagine simply compressing the jpeg's and perhaps losing some quality would help, but my understanding is the iPhone does its own image compression/decompression on the device and I may be wasting my time.
Tried different things, eventually hit on storing an array of NSData objects and converting to UIImage on the fly.
for (NSString *imageFile in directoryList) {
NSString *fileLocation = [imageFolder stringByAppendingPathComponent:imageFile];
NSData *imageData = [NSData dataWithContentsOfFile:fileLocation];
if (imageData) {
[images addObject:imageData];
} else {
[Util trace:#"cannot get image data for image named: %#", fileLocation];
}
and then to update your image:
-(void)updateImageView:(id)sender
{
UIImage *anImage = [UIImage imageWithData:[images safeObjectAtIndex:nextImage] ];
[imageView setImage:anImage];
nextImage++;
}

Selectively loading low-resolution resources in iOS when #2x-version is also present

I had a lot of trouble trying to force the loading of the low-resolution version of some resources on iOS, when the high-res version (#2x) is also present.
The reason I wanted to do this is simple: My app shows a bunch of full-screen images to the user (320x480 on older devices, 640x960 on Retina devices), and the user can upload some of these to TwitPic. I wanted to unify the uploaded images to 320x480, regardless of the device (for consistency, because that size is fine in a web browser).
I found out that no matter what UIImage method I used, when the high-resolution version of a resource file is present it is loaded (even if you pass the full file path): UIImage will out-smart you. But I found a way to out-smart UIImage:
- (UIImage*) lowResImage{
NSString* path = [[NSBundle mainBundle] pathForResource:_fileName
ofType:#"png"
inDirectory:_resourceSubdirectory];
path = [path stringByReplacingOccurrencesOfString:#"##2x" withString:#""];
NSData* imageData = [[NSData alloc] initWithContentsOfFile:path];
UIImage* image = [[UIImage alloc] initWithData:imageData];
[imageData release];
return [image autorelease];
}
The above code works fine on a 4th generation iPod touch.
Anybody came up with a better approach?
Build your path, open data, and then init the image using data as in the example below.
NSString *dataPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:_fileName];
NSData *data = [[NSData alloc] initWithContentsOfFile:dataPath];
UIImage *image3 = [UIImage imageWithData:data];

Resources