I am writing images to the directory of my app using the following code in a separate thread
for (int j =0; j<[sorted count]; j++) {
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[sorted objectAtIndex:j]]];
UIImage *image = [UIImage imageWithData:data];
if (image!=nil) {
NSLog(#"%#",[sorted objectAtIndex:j]);
[images addObject:image];
}
}
and
for (int k=0;k<[images count];k++)
{
NSString *temp = [[sorted objectAtIndex:k]lastPathComponent];
NSString *imagePath = [dataPath stringByAppendingPathComponent:temp];
NSData *data = UIImageJPEGRepresentation([images objectAtIndex:k], 1.0f);
[data writeToFile:imagePath atomically:YES];
}
But a weird thing is last two images are not getting written
I've tried everything but it doesn't seem to work.
Anyone have any idea about this?
Not sure what could be causing your issue, but UIKit is not thread safe, so this could be the cause. You could try and execute your code on the main thread just to troubleshoot it (and check that it is correct), then, if my guess is right, look for a workaround.
In looking for a workaround, possibly performSelector:onMainThread: could help.
Related
I have the following code below to populate an array with images:
NSString *fileName;
myArray = [[NSMutableArray alloc] init];
for(int i = 1; i < 285; i++) {
fileName = [NSString stringWithFormat:#"Animation HD1.2 png sequence/HD1.2_%d.png", i];
[myArray addObject:[UIImage imageNamed:fileName]];
NSLog(#"Loaded image: %d", i);
}
In my resources folder i have #2x versions of each of these images. Is there a way (programmatically) that I can ignore the #2x images on retina devices and populate the array with the non-#2x images?
EDIT 1:
I've edited my code to use NSData:
myArray = [[NSMutableArray alloc] init];
for(int i = 1; i < 285; i++) {
fileName = [NSString stringWithFormat:#"Animation HD1.2 png sequence/HD1.2_%d.png", i];
NSData *fileData = [NSData dataWithContentsOfFile:fileName];
UIImage *regularImage = [UIImage imageWithData:fileData];
[myArray addObject:regularImage];
}
falling.animationImages = MYArray;
This is crashing my app with the error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'. Am i using the NSData object wrong?
I believe the question amounts to "How do I bypass the automatic #2x image loading?"
You need to take a path it can't follow. You could pass the contents of each file using NSData dataWithContentsOfFile:options:error: to UIImage imageWithData: This way, imageWithData won't know where the data came from, let alone that there's a 2x version.
I think the NSData technique should work, but you need to get the path from your bundle, you can't just give the filename as a string like that.
Try:
filename = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"Animation HD1.2 png sequence/HD1.2_%d.png", i] ofType:nil];
Try this...
//This string will have #"#2x.png"
NSString *verificationString = [myString substringFromIndex:[myString length] - 7];
if(![verificationString isEqualToString:#"#2x.png"])
{
//NOT EQUAL...
}
My problem is same as Converting byte array coming from Web service to UIImage iPhone
.Now I am storing these bytes in NSMutableArray.But the method:
NSData *data = [NSData dataWithBytes:YOUR_BYTE_ARRAY length:ARRAY_LENGTH];
takes arrayOfBytes as parameter.So can anyone tell me that how to convert this array in byte array. I searched a lot but unable to find relevant contents.
Not sure how you're getting the mutable array to begin with. If you're using NSURLConnection, the delegate will get NSData, so you needn't use a mutable array. Consider getting the data using the connection asynch block method like this ...
NSURLRequest *myRequest = // the request you've already got working to get image data
[NSURLConnection sendAsynchronousRequest:myRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
// image from data with no intermediate mutable array or byte array
UIImage *image = [UIImage imageWithData:data];
}
}];
Thanks for your co-operation. But it does not help me. After a long research i found my solution. I am sharing my information so that others can get right answer.
NSArray *byteArray = [[NSArray alloc]init]; //strore all data here coming from server in byte formate
unsigned c = [byteArray count];
uint8_t *bytes = malloc(sizeof(*bytes) * c);
unsigned i;
for (i = 0; i < c; i++)
{
NSString *str = [byteArray objectAtIndex:i];
int byte = [str intValue];
bytes[i] = (uint8_t)byte;
}
NSData *data = [[NSData alloc]initWithBytes:bytes length:c];
UIImage *image = [UIImage imageWithData:data];
NSLog(#"image %#",image);
I am fetching URL of the images from the server and converting this images into png format using:
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(img)];
[data1 writeToFile:pngFilePath atomically:YES];
but some of the images are corrupted when i check them after completing the process on simulator.
Hence these images are not displaying on the app wherever needed.
Please see the attached image as some images are corrupted.
Update
I am calling a method in a loop which fetches the images from the server parallel and didFinishLoading I am performing this:
UIImage *img = [UIImage imageWithData:self.data];
NSArray *split = [self.strImageName componentsSeparatedByString:#"/"];
int arrCount=[split count];
NSString *imageName=[split objectAtIndex:arrCount-1];
NSString *docDirec = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *pngFilePath=nil
pngFilePath = [NSString stringWithFormat:#"%#/Thumbs/%#",docDirec,imageName];
NSData *data1 = [NSData dataWithData:UIImagePNGRepresentation(img)];
[data1 writeToFile:pngFilePath atomically:YES];
[self.data release]; //don't need this any more, its in the UIImageView now
self.data=nil;
i have the similar problem
i solved it using the below code
- (void)viewWillDisappear:(BOOL)animated
{
if (self.m_objWebManager != nil)//Webmanager is class for downloading the images as a background thread
{
[self.m_objWebManager cancelCommunication];
[self.m_objWebManager release];
self.m_objWebManager = nil;
}
}
I'm creating some temporary files in the iPad simulator. To test my file creation, I create the file and then read it back. Here's some code to show this:
-(NSString *) writeToTempFile:(UIImage*) image{
NSString *path = [self createTemporaryFile];
NSLog(#"path: %#", path);
NSData *data = UIImageJPEGRepresentation(image, 1);
[data writeToFile:path atomically:YES];
free(data);
return path;
}
-(UIImage *) readTempFile:(NSString *) path{
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:data];
return image;
}
I call these methods one after another, before a final function writes out the UIImage to the photo album.
UIImageWriteToSavedPhotosAlbum(image2, self, nil, nil);
The problem is, this always crashes my app on the third time it is executed. First and second time it successfully does all of this and stores to the album. Third time it crashes to Home. Any ideas?
NSData *data = UIImageJPEGRepresentation(image, 1);
[data writeToFile:path atomically:YES];
free(data);
The NSData returned from UIImageJPEGRepresentation is -autoreleased. There is no need to free() it. And it is wrong to free() any Objective-C objects — send a -release message instead.
Please read through the Memory Management Programming Guide.
I had the following code that takes in 14 mb or more of image data encoded in base4 string and converts them to jpeg before writing to a file in iphone. It crashes my program giving the following error :
Program received signal: “0”.
warning: check_safe_call: could not restore current frame
I tweak my program and it can process a few more images before the error appear again. My coding is as follows:
// parameters is an array where the fourth element contains a list of images in base64 >encoded string
NSMutableArray *imageStrList = (NSMutableArray*) [parameters objectAtIndex:5];
while (imageStrList.count != 0) {
NSString *imgString = [imageStrList objectAtIndex:0];
// Create a file name using my own Utility class
NSString *fileName = [Utility generateFileNName];
NSData *restoredImg = [NSData decodeWebSafeBase64ForString:imgString];
UIImage *img = [UIImage imageWithData: restoredImg];
NSData *imgJPEG = UIImageJPEGRepresentation(img, 0.4f);
[imgJPEG writeToFile:fileName atomically:YES];
[imageStrList removeObjectAtIndex:0];
}
I tried playing around with UIImageJPEGRepresentation and found out that the lower the value, the more image it can processed but this should not be the way. I am wondering if there is anyway to free up memory of the imageStrList immediately after processing each image so that it can be used by the next one in the line.
Your problem is that the UIImages and NSDatas are piling up in memory in a loop. Normally the autorelease pool would take care of this at the end of the event loop, but you're not letting it get that far. You have two choices:
Explicitly allocate/init and then release when done the UIImage and NSData objects, rather than using the +class methods.
Create an explicit autorelease pool inside the loop, and drain it at the end. Do this with:
NSAutoreleasePool * myPool = [[NSAutoreleasePool alloc] init];
[myPool release];
NSMutableArray *imageStrList = (NSMutableArray*) [parameters objectAtIndex:5];
while (imageStrList.count != 0) {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
NSString *imgString = [imageStrList objectAtIndex:0];
// Create a file name using my own Utility class
NSString *fileName = [Utility generateFileNName];
NSData *restoredImg = [NSData decodeWebSafeBase64ForString:imgString];
UIImage *img = [UIImage imageWithData: restoredImg];
NSData *imgJPEG = UIImageJPEGRepresentation(img, 0.4f);
[imgJPEG writeToFile:fileName atomically:YES];
[imageStrList removeObjectAtIndex:0];
[pool release];
}
You should create another autoreleasepool inside the loop because objects created inside loop won't be released until the program get out from the loop.
Auto release pool inside the loop will release all objects created inside the loop every time.