Null value causing crash even with if/else statement? - ios

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 {
}

Related

Need to set the image from URL without any blink. Read the description to know the complete scenario

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

imageView blank when set with URL?

I'm using the below to set my imageView with a url (located in path). Yes, the URL data is returned successfully, but for some reason, my imageView remains blank (just white?)
And yes, I've hooked up my imageView property... Any idea what's wrong? Should I be using a different block of code to accomplish this?
Viewcontroller.m
NSMutableDictionary *viewParamsDogs = [NSMutableDictionary new];
[viewParamsDogs setValue:#"mydogs" forKey:#"view_name"];
[DIOSView viewGet:viewParamsDogs success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.dogData = [responseObject mutableCopy];
[operation responseString];
NSDictionary *dic = [responseObject valueForKey: #"field_pet_photo_path"];
NSArray *arr = [dic valueForKey: #"und"];
NSDictionary *dic2= [arr objectAtIndex : 0];
NSString *path = [NSString stringWithFormat:#"%#", [dic2 valueForKey: #"safe_value"]];
NSLog(#"This is path %#", path);
if([path length]>0) {
NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
self.dogimageView.image = image;
} else {
NSString *ImageURL = #"http://url.ca/paw.png";
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
self.dogimageView.image = [UIImage imageWithData:imageData];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
Path:
[5111:1673330] This is path (
"http://url.com/default/files/stored/1460659054.jpg"
)
NSLog(#"This is path %#, %#", path, NSStringFromClass(path.class)); returns:
2016-04-14 13:18:39.590 [5225:1700657] This is path (
"http://url.com/default/files/stored/1460659054.jpg"
), __NSCFString
I recommend usage of AFNetworking https://github.com/AFNetworking/AFNetworking for all networking connect features.
Import UIImageView+AFNetworking.h at beginning of file
#import "UIImageView+AFNetworking.h"
Get path from dic2
NSString *path = dic2[#"safe_value"];
Check if path is a string
if (![path isKindOfClass:[NSString class]]) {
return;
}
Create a NSURL object from string
NSURL *imageUrl = [NSURL URLWithString:path];
Set imageUrl to UIImageView
[self.dogimageView setImageWithURL:imageUrl];
You could check the full code in my gist https://gist.github.com/MaciejGad/fa8cb80dfc73ea55edeedb75418ea2ec
Edit:
the reason of error was the path that was set as:
NSString *path = #"(
\"http://url.com/default/files/stored/1460659054.jpg\"
)";
to change to normal URL we need to trim it:
NSMutableCharacterSet *characterSetToTrim = [NSMutableCharacterSet characterSetWithCharactersInString:#"()\""];
[characterSetToTrim formUnionWithCharacterSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
path = [path stringByTrimmingCharactersInSet:characterSetToTrim];
after this trimming path should be http://url.com/default/files/stored/1460659054.jpg
Try like this,
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
self.dogimageView.image = [[UIImageView alloc] initWithImage:image];
and You can use great library SDWebImage for caching image. When image comes from server use of this library is very helpful. Hope this will work.
Update :
NSString *path = [NSString stringWithFormat:#"%#", [dic2 valueForKey: #"safe_value"]];
NSURL *url = [NSURL URLWithString:path];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
self.dogimageView.image = [[UIImageView alloc] initWithImage:image];
Try this. :)
Try using dataWithContentsOfURL:options:error: instead and look if there is any error message there

Set NSString with returned JSON value

I'm trying to set my imageView with the url returned in the JSON data below in "value" (secondLink). When I use the following code, it returns the entire block in JSON through my XCode console - what should my code look like if I ONLY want the image's URL to be returned (right now, I assume it's trying to set the imageView with EVERYTHING returned in secondLink)?
ViewController.m
NSString *secondLink = [[[[DIOSSession sharedSession] user] objectForKey:#"field_photo_path"] objectForKey:#"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];
} else {
NSString *ImageURL = #"defaulturl.com";
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
self.imageView.image = [UIImage imageWithData:imageData];
}
JSON data
{
und = (
{
format = "<null>";
"safe_value" = "http://myurl.com/sites/default/files/stored/photo.jpg";
value = "http://myurl.com/sites/default/files/stored/photo.jpg";
}
);
}
In field_photo_path there is a dictionary und which contains an array.
The first item in the array is a dictionary containing the key safe_value.
It assumes that user is also a dictionary (at least it responds to objectForKey:)
NSDictionary *user = [[DIOSSession sharedSession] user];
NSString *secondLink = user[#"field_photo_path"][#"und"][0][#"safe_value"];

How to use nscache to download image from api.?

I have a UIImageview in UICollectionview cell and parse the image data from api and add to UIImageview. Now everything is going perfect but there is some problem I face during scroll down, when I tried to scroll UICollectionview cell its going hang.
Now I need to use NSCache to download image and than add it to UIImage, but I am unable to do this task I am stuck somewhere in my code, I don't know where. Please look at my code.
-(UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
OneTimeCell *cell = (OneTimeCell*)[collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.selected = YES;
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
cell.productname.text = [[productname objectAtIndex:indexPath.row] objectForKey:#"product_name"];
cell.productnumber.text = [[productname objectAtIndex:indexPath.row] objectForKey:#"id"];
NSString *image = [[productname objectAtIndex:indexPath.row] objectForKey:#"image" ];
NSLog(#"image %#", image);
NSURL *baseURL = [NSURL URLWithString:#"http://dev1.brainpulse.org/ecoware1//app/webroot/img/uploads/Product/thumb/"];
NSURL *url = [NSURL URLWithString:image relativeToURL:baseURL];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage * productimage = [UIImage imageWithData:imageData];
NSURL *absURL = [url absoluteURL];
NSLog(#"absURL = %#", absURL);
if (productimage) {
cell.productimage.image = productimage;
}
else
{
cell.productimage.image = [UIImage imageNamed:#"icon_1.png"];
[self.imageDownloadingQueue addOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:image relativeToURL:baseURL];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImageView *image = nil;
if (image) {
[self.imageCache setObject:image forKey:imageData];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
OneTimeCell *cell =[collectionView cellForItemAtIndexPath:indexPath];
if (cell) {
cell.productimage.image = image;
}
}];
}
}];
}
return cell;
}
in your code line 10 you fetching image on mainthread that is why your cell got stuck . . .Please replace that code with this one
Replace this code
NSString *image = [[productname objectAtIndex:indexPath.row] objectForKey:#"image" ];
NSLog(#"image %#", image);
NSURL *baseURL = [NSURL URLWithString:#"http://dev1.brainpulse.org/ecoware1//app/webroot/img/uploads/Product/thumb/"];
NSURL *url = [NSURL URLWithString:image relativeToURL:baseURL];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage * productimage = [UIImage imageWithData:imageData];
NSURL *absURL = [url absoluteURL];
NSLog(#"absURL = %#", absURL);
With This one
NSString *image = [[productname objectAtIndex:indexPath.row] objectForKey:#"image" ];
NSLog(#"image %#", image);
NSURL *baseURL = [NSURL URLWithString:#"http://dev1.brainpulse.org/ecoware1//app/webroot/img/uploads/Product/thumb/"];
NSURL *url = [NSURL URLWithString:image relativeToURL:baseURL];
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
NSData * imageData = [NSData dataWithContentsOfURL:url];
dispatch_async(dispatch_get_main_queue(), ^{
UIImage * productimage = [UIImage imageWithData:imageData];
});
});
NSURL *url = #"................";
ImageRequest *request = [[ImageRequest alloc] initWithURL:url];
UIImage *image = [request cachedResult];
if (image) {
// Set the image if exist
} else {
[request startWithCompletion:^(UIImage *image, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if(image) {
cell.productimage.image = productimage;
}else {
// Set any placeholder image here.......
}
});
}];
}
NSString *image = [[productname objectAtIndex:indexPath.row] objectForKey:#"image" ];
NSLog(#"image %#", image);
NSURL *baseURL = [NSURL URLWithString:#"http://dev1.brainpulse.org/ecoware1//app/webroot/img/uploads/Product/thumb/"];
NSURL *url = [NSURL URLWithString:image relativeToURL:baseURL];
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
//NSData * imageData = [NSData dataWithContentsOfURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
if(data)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIImage * productimage = [UIImage imageWithData:data];
});
}
}];
});

Convert UIImage to NSData and save with core data

I have a UIImageView whose image gets set via UIImagePicker
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[picker dismissViewControllerAnimated:YES completion:nil];
self.gImage.image = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
}
I "attempt" to convert this image to NSData and save it with core data:
NSData *imageData = UIImagePNGRepresentation(self.gImage.image);
NSString *savedData = [[NSString alloc]initWithData:imageData encoding:NSUTF8StringEncoding];
//am is a pointer to my entities class. imageData is just a NSString attribute
am.imageData = savedData;
NSError *error;
if (![self.managedObjectContext save:&error]) {
//Handle Error
} else {
[self dismissViewControllerAnimated:YES completion:nil];
}
Then I try to load the image in a separate file:
self.cell.gImage.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.myEntity.imageData]]];
I cannot see why this is not working. Any help is greatly appreciated!
You can convert a UIImage to NSData like this:
If PNG image
UIImage *image = [UIImage imageNamed:#"imageName.png"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
If JPG image
UIImage *image = [UIImage imageNamed:#"imageName.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
You can store it in CoreData like so (this is one possible useful solution):
[newManagedObject setValue:imageData forKey:#"image"];
You can load the data from CoreData like this:
NSManagedObject *selectedObject = [[self yourFetchCOntroller] objectAtIndexPath:indexPath];
UIImage *image = [UIImage imageWithData:[selectedObject valueForKey:#"image"]];
// Set the image to your image view
yourimageView.image = image;
For swift its just:
UIImage to NSData
imageData = UIImagePNGRepresentation(image)
For storing in database:::
NSInteger RandomIndex = arc4random() % 1000;
NSString *randomImageName =[NSString stringWithFormat:#"Image%i.png",RandomIndex];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:randomImageName];
if ([[NSFileManager defaultManager] fileExistsAtPath:savedImagePath]) {
[[NSFileManager defaultManager] removeItemAtPath:savedImagePath error:nil];
NSLog(#"file removed from path");
}
NSLog(#"Saved Image Path : %#",savedImagePath);
NSData* imageData = UIImagePNGRepresentation (image1 );
[imageData writeToFile:savedImagePath atomically:YES];
//am is a pointer to my entities class. imageData is just a NSString attribute
am.imageData = randomImageName;
When you get that image from data base, you can write following code...
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:randomImageName];
NSData *myData = [NSData dataWithContentsOfFile:savedImagePath];
UIImage *selectedImage = [UIImage imageWithData:myData];
I think it is helpful to you.
On Mac OS you can let Core Data handle this for you by ticking the Transformable box on the attribute in the model, not selecting a specific transformer, and assigning the UIImage directly to the property.
I'm not sure if it works on iOS but it might be worth a try.
To convert an image to NSData try below code...
UIImage *image = [UIImage imageNamed:#"imageName.png"];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(image)];
let me know it is working or not..!!!
Happy Coding!!!!
Try This Code to save image data
to save:
NSManagedObjectContext *context = [self managedObjectContext];
newsObj = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
NSData *imageData = UIImagePNGRepresentation(self.gImage.image);
[newsObj setValue:imageData forKey:#"imgPng"];
NSError *error;
#try{
if (managedObjectContext != nil) {
if (![managedObjectContext save:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
}
}#catch (NSException *exception) {
NSLog(#"inside exception");
}
To Retrive Try this:
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity1 = [NSEntityDescription entityForName:#"Event" inManagedObjectContext:context];
[fetchRequest setEntity:entity1];
NSError *error;
NSArray * array = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
if (array == nil) {
NSLog(#"Testing: No results found");
}else {
NSLog(#"Testing: %d Results found.", [array count]);
}
NSData * dataBytes = [[array objectAtIndex:0] imgPng];;
image = [UIImage imageWithData:dataBytes];
[fetchRequest release];
}
#catch (NSException *exception) {
NSLog(#"inside exception");
}
This code save your image data into filedata and you can use it anywhere
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image1 editingInfo:(NSDictionary *)editingInfo
{
{
CGSize destinationSize = CGSizeMake(170,170);
UIGraphicsBeginImageContext(destinationSize);
[image1 drawInRect:CGRectMake(0,0,destinationSize.width,destinationSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NsData *filedata = UIImagePNGRepresentation(newImage);
[picker dismissModalViewControllerAnimated:YES];
}
}
Here is what I have done and its working for storing to nsdata.
[productTypeSub setValue:[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]] forKey:#"imgSmall"];
and loading to image with this code
ImgProductType.image= [[UIImage alloc] initWithData:productTypeSub.imgSmall];

Resources