I have a problem with my iOS app I cannot solve. It keeps quitting and sometimes the whole iPhone restarts when there are other apps open (even background ones).
When looking with the profiling tools provided with xCode it seems that “ImageIO_JPEG_Data” uses all the ram available.
I attach you the images from the profiler. If you need anything else please let me know!!
EDIT: found it! That’s the code causing it
-(void)downloadFromURL:(NSString *)url withPlaceholder:(UIImage *)placehold
{
if (placehold) {
[self setImage:placehold];
}
if (url) {
if ([url rangeOfString:#"/Library/"].location != NSNotFound) {
NSData *imageData=[NSData dataWithContentsOfFile:url];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
[self setImage:image];
[self setNeedsLayout];
}
return;
}
NSString *strImgName = [[[[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] componentsSeparatedByString:#"/"] lastObject] retain];
AppDelegate *app=[[UIApplication sharedApplication]delegate];
[app applicationCacheDirectoryString];
// NSString *imagePath = [NSString stringWithFormat:#"%#%#",[[AppDelegate sharedObject]applicationCacheDirectoryString],strImgName];
NSString *imagePath = [NSString stringWithFormat:#"%#%#",[app applicationCacheDirectoryString],strImgName];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *aURL=[url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if ([fileManager fileExistsAtPath:imagePath]==NO)
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:aURL]];
[imageData writeToFile:imagePath atomically:YES];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:image];
[self setNeedsLayout];
});
}
});
}
else{
NSData *imageData=[NSData dataWithContentsOfFile:imagePath];
UIImage* image = [[UIImage alloc] initWithData:imageData];
if (image) {
[self setImage:image];
[self setNeedsLayout];
}
}
}
}
Apparently it wasn’t a bug in my code causing it, somehow the sqlite database I was using got corrupted and removing the app and reinstalling it seems to have fixed it.
Related
I am uploading the image from the ImagePicker and once the image is upload on the server I show it from URL. So from local image to URL image, there comes a blink, which I want to avoid but I am unable to fix it. Any suggestion will be really helpful. I am adding the code below:
- (void)setDataOnCell:(NSDictionary *)dict {
self.messageTimeLabel.text = [CommonUtils checkForNUllValue:[dict valueForKey:#"msg_time"]];
if (![[CommonUtils checkForNUllValue:[dict valueForKey:#"msg_status"]] isEqualToString:#"Read"]) {
self.messageTickImageView.image = [UIImage imageNamed:#"check_delivered_icon"];
self.messageStatusLabel.textColor = [UIColor colorWithRed:166.0f/255.0f green:166.0f/255.0f blue:166.0f/255.0f alpha:1.0];
}
else {
self.messageTickImageView.image = [UIImage imageNamed:#"check_read_icon"];
self.messageStatusLabel.textColor = [UIColor colorWithRed:254.0f/255.0f green:223.0f/255.0f blue:224.0f/255.0f alpha:1.0];
}
self.messageStatusLabel.text = [CommonUtils checkForNUllValue:[dict valueForKey:#"msg_status"]];
if ([[NSString stringWithFormat:#"%#", [dict valueForKey:#"attachment_type"]] isEqualToString:#"local_img"]){
self.messageImageview.image = [dict valueForKey:#"attachment"];
}
else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#", [NSString stringWithFormat:#"%#", [dict valueForKey:#"attachment"]]]];
NSData *urlData = [NSData dataWithContentsOfURL:imageURL];
//This is your completion handler
dispatch_sync(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:urlData];
self.messageImageview.image = image;
});
});
}
}
first of all you need to set a default image on this image view after that you call image by url and set on this
NSOperationQueue *queueThumbnl = [[NSOperationQueue alloc] init];
[queueThumbnl setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];
[queueThumbnl addOperationWithBlock:^{
// Background work
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#", [NSString stringWithFormat:#"%#", [dict valueForKey:#"attachment"]]]];
NSData *urlData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:urlData];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:self.messageImageview, #"messageImageview", urlData, #"imageData", nil];
[self performSelectorOnMainThread:#selector(mainThreadUIUpdate:) withObject:dict waitUntilDone:YES];
// [self updateThumbnailOnMainThread:anItem setImageTo:cell];
}];
-(void)mainThreadUIUpdate:(NSDictionary *)dict
{
UIImageView *messge = [dict objectForKey:#"messageImageview"];
UIImage *image = [dict objectForKey:#"image"];
[messge.imageView setImage:image];
[cell.imageView setNeedsDisplay:YES];
}
I am trying to fetch images on a button click in Viewcontroller B .After the image is received as response,I use the url of images to populate the imageviews on viewcontroller.But,it is taking too long to get populated and also hangs while scrolling.Is there any way to scroll the view smoothly without freezing and get the response little early.
This line should not be in main queue
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[responseArr objectAtIndex:indexPath.row]valueForKey:#"CategoryImage"]]];
you may change to something like this
NSString *getImagePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.jpeg",n1.Id]];
if([[NSFileManager defaultManager] fileExistsAtPath:getImagePath])
{
UIImage *img = [UIImage imageWithContentsOfFile:getImagePath];
cell.leftImageV.image =img;
[cell.activity stopAnimating];
cell.activity.hidden=YES;
}
else
{
[cell.activity startAnimating];
cell.activity.hidden=NO;
cell.leftImageV.image = nil;
NSLog(#"xdasdxsadxa %#",n1.mainImgStr);
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block NSData * imageData = nil;
dispatch_sync(concurrentQueue, ^{
imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:n1.mainImgStr]];
//Add the file name
[imageData writeToFile:getImagePath atomically:YES]; //Write the file
});
dispatch_sync(dispatch_get_main_queue(), ^{
if(imageData)
{
[self.collectionView reloadData];
}
});
});
}
Use dispatch async for image retrieve, namely, don't do it on main queue.
Apple Doc:
https://developer.apple.com/documentation/dispatch/1453057-dispatch_async
I'm having the strangest issue. I'm using the below code to display the profile photo of a logged in user (I'm retrieving the image from a field in my Drupal database).
.m
//USER PHOTO
NSDictionary *user = [[DIOSSession sharedSession] user];
NSString *secondLink = user[#"field_photo_path"][#"und"][0][#"safe_value"];
NSLog(#"This is second link %#", secondLink);
if([secondLink length]>0) {
NSString *ImageURL = secondLink;
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
// self.imageView.image = [UIImage imageWithData:imageData];
self.imageView.image = [[UIImage alloc] initWithData:imageData];
} else {
NSString *ImageURL = #"http://url.com/default.png";
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
self.imageView.image = [UIImage imageWithData:imageData];
}
Naturally, if secondLink is null (or empty, e.g. no photo has been uploaded), I receive the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArray0
objectForKeyedSubscript:]: unrecognized selector sent to instance
0x14f602fe0'
I thought I solved this issue with the if/else statement, but apparently not. How can I fix this?
Cheers!
NSString *secondLink = user[#"field_photo_path"][#"und"][0][#"safe_value"];
You need to verify that the user dictionary is valid before reading that far into it.
if (user[#"field_photo_path"]) {
// you can look for [#"und"] here
// providing it is a dictionary and not an array
if([user[#"field_photo_path"] isKindOfClass:[NSDictionary class]]){
if (user[#"field_photo_path"][#"und"]) {
// etc
}
}
}
You can reduce this nested code by modelling a User class as an NSObject subclass and include methods in that class to parse this data safely, allowing you to only write this validation code in one place.
Edit
As mentioned in a comment:
If the data in user[#"field_photo_path"][#"und"] is an NSDictionary and not an NSArray you cannot access it with [0] and will get your crash. You access NSArray's with an index (array[0], array[1] etc) and an NSDictionary with a key (dict[#"name"], dict[#"und"] etc)
Solution is to put check on on your key's
//USER PHOTO
NSDictionary *user = [[DIOSSession sharedSession] user];
if (user[#"field_photo_path"]) {
if ([user[#"field_photo_path"] isKindOfClass:[NSDictionary class]]) {
if (user[#"field_photo_path"][#"und"]) {
if ([user[#"field_photo_path"][#"und"]isKindOfClass:[NSArray class]]) {
if ([user[#"field_photo_path"][#"und"] count]>0) {
if (user[#"field_photo_path"][#"und"][0][#"safe_value"]) {
if ([user[#"field_photo_path"][#"und"][0][#"safe_value"] isKindOfClass:[NSDictionary class]]){
NSString *secondLink = user[#"field_photo_path"][#"und"][0][#"safe_value"];
NSLog(#"This is second link %#", secondLink);
if([secondLink length]>0) {
NSString *ImageURL = secondLink;
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
// self.imageView.image = [UIImage imageWithData:imageData];
self.imageView.image = [[UIImage alloc] initWithData:imageData];
} else {
NSString *ImageURL = #"http://url.com/default.png";
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
self.imageView.image = [UIImage imageWithData:imageData];
}
}
}
}
}
}
}
}
You can also use try catch block to avoid crashing
#try {
//USER PHOTO
NSDictionary *user = [[DIOSSession sharedSession] user];
NSString *secondLink = user[#"field_photo_path"][#"und"][0][#"safe_value"];
NSLog(#"This is second link %#", secondLink);
if([secondLink length]>0) {
NSString *ImageURL = secondLink;
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
// self.imageView.image = [UIImage imageWithData:imageData];
self.imageView.image = [[UIImage alloc] initWithData:imageData];
} else {
NSString *ImageURL = #"http://url.com/default.png";
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
self.imageView.image = [UIImage imageWithData:imageData];
}
}
#catch (NSException *exception) {
//Handle expecption
}
#finally {
}
I'm creating a stack of images in my viewdidload method. The images are from PFFile's from parse so they contain the fileURL of my image data.
My problem is that these two lines of code are dramatically slowing down my app and killing my user experience:
//get scene object
PFObject *sceneObject = self.scenes[i];
//get the PFFile and filetype
PFFile *file = [sceneObject objectForKey:#"file"];
NSString *fileType = [sceneObject objectForKey:#"fileType"];
//check the filetype
if ([fileType isEqual: #"image"])
{
//get image
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl]; ********** these
imageView.image = [UIImage imageWithData:imageData]; ********************* lines
}
How do I get this image/these images (this is nested in a for loop) more quickly? I've already downloaded my PFObjects that contain the PFFiles and stored them locally.
I guess I really don't understand how file URL's operate.
Thank you.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURL *imageFileUrl = [[NSURL alloc] initWithString:file.url];
NSData *imageData = [NSData dataWithContentsOfURL:imageFileUrl];
dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:imageData];
});
});
Have not tested but this is the gist. Get the file loading off the main queue and make it asynchronous. The UI will not be bogged down because as soon as this queue is dispatched it's going to return and keep evaluating the rest of your application.
I am using somethig like this:
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[imageFrame addSubview:activityIndicator];
activityIndicator.center = CGPointMake(imageFrame.frame.size.width / 2, imageFrame.frame.size.height / 2);
[activityIndicator startAnimating];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData * imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:thumb]];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *image = [UIImage imageWithData:imageData];
img.image = image;
[imageOver addSubview:img];
[activityIndicator removeFromSuperview];
});
});
I'm trying to share an image after i download it from the server to instagram, this is the code i`m using to download the image form the server
- (IBAction) DownloadImage:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:sender];
NSData *data = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *viewImage = [[UIImage alloc] initWithData:data];
UIImageWriteToSavedPhotosAlbum(img, self, #selector(image:didFinishSavingWithError:contextInfo:), (__bridge void *)(img));
});
});
}
now the image is saved to photo album, how can open it in instagram app directly after it have been downloaded ?
image size is always more than 612x612px
After a while i found the answer and modified it to my code
#property (nonatomic, retain) UIDocumentInteractionController *dic;
- (IBAction) DownloadImage:(id)sender {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURL *url = [NSURL URLWithString:sender];
NSData *data = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage *screenShot = [[UIImage alloc] initWithData:data];
NSString *imagePath = [NSString stringWithFormat:#"%#/image.igo", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]];
[[NSFileManager defaultManager] removeItemAtPath:imagePath error:nil];
[UIImagePNGRepresentation(screenShot) writeToFile:imagePath atomically:YES];
_dic = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:imagePath]];
_dic.delegate = self;
_dic.UTI = #"com.instagram.exclusivegram";
NSURL *instagramURL = [NSURL URLWithString:#"instagram://media?id=MEDIA_ID"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[self.dic presentOpenInMenuFromRect:self.view.frame inView:self.view animated:YES];
}
else {
NSLog(#"no instagram app found");
}
});
});
}