Why are characters and forward slashes being appended to my NSURL? - ios

My images are not loading from their URLs. When I log the NSURL, it appears correct
my.website.com/images/image1.png
But when I set breakpoints, the NSURL shows up in the debugger console as
my.website.com/images/image1.png\x05\b
I have checked the json through my web browser, and it is perfectly valid. The string ends with the 'g' of "png".
I am using SDWebImage to asynchronously load images for my table cells. The URLs to be used for the pictures are coming from a php file that encodes the JSON.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
SpotsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"SpotCell" forIndexPath:indexPath];
NSInteger row = indexPath.row;
if (self.spotDictionary)
{
NSDictionary* spot = (NSDictionary*)[self.spotDictionary objectForKey:[NSString stringWithFormat:#"%d", row]];
NSString* title = [spot objectForKey:#"Title"];
NSURL* imageURL = [NSURL URLWithString:(NSString*)[spot objectForKey:#"Image"]]; NSLog(#"%#", imageURL);
UIImage* placeholder = [UIImage imageNamed:#"placeholder.png"];
// See ~*~ below
NSURL* testURL = [NSURL URLWithString:#"http://www.hdwallpaperspot.com/wp-content/uploads/2013/08/Volvo-station-wagon-612pb.jpg"];
cell.nameLabel.text = title;
[cell.pictureView setImageWithURL:imageURL
placeholderImage:placeholder]; // SDWebImage category for UIImage
//breakpoint here
}
return cell;
}
~*~
To make sure SDWebImage was performing correctly, I grabbed an image off the net to temporarily test the library, and it performed wonderfully. I have checked the class of the "Image" object and it is _NSCFString. The (NSString*) cast was added in case my understanding of the interchangeability between NSCFString and NSString is flawed. No luck.

This is very embarrassing, but I'll share my mistake so no one gets misconcepted.
I forgot to specify the protocol (http://) in my Image JSON object.
I figured NSURL class would have some sort of default HTTP checking, but I realize that's not feasible, as there are other protocols that could be used with an NSURL.
Thanks #rmaddy for pointing out the debugger, uhm, bug.

Related

SDWebImage is not loading images from NSDictionary

I have a UITableView and I am loading some articles from an RSS file with keys: title, url and image url. I am trying to display the image in the UITableViewCell using the SDWebImage library and when I "load" the image through the dictionary that is downloaded from the RSS the image is not loaded. The url of the image though is loaded successfully and printed exactly before the load. But when I copy the printed url and paste it in another string trying to load that url it works. Below is my code.
NSString *urlofimage = [[feeds objectAtIndex:indexPath.row] objectForKey: #"image"];
NSLog(#"%#", urlofimage);
NSString *urlofimage1 = #"https://www.radioevros.gr/wp-content/uploads/2017/05/1495542572-74c82f60669c9db27cad113d22379c72.jpg";
[cell.imageview sd_setImageWithURL:[NSURL URLWithString:urlofimage] placeholderImage:[UIImage imageNamed:#"radio.png"]
options:SDWebImageRefreshCached];
So, my code doesnt seem to be wrong since I was working with the same code before and it was working. In the code above, the urlofimage1 is actually a printed url from the urlofimage. And if I do this:
[cell.imageview sd_setImageWithURL:[NSURL URLWithString:urlofimage1] placeholderImage:[UIImage imageNamed:#"radio.png"]
options:SDWebImageRefreshCached];
is working, but if I do this is not.
[cell.imageview sd_setImageWithURL:[NSURL URLWithString:urlofimage] placeholderImage:[UIImage imageNamed:#"radio.png"]
options:SDWebImageRefreshCached];
This is loaded inside :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Any ideas? Thank you.
I would suspect that you have some invalid characters in your dictionary, like a space at the end or something similar what is hard to spot.
Try encoding your received string first, and than create your NSURL instance.
NSString *urlofimage = #"https://www.radioevros.gr/wp-content/uploads/2017/05/1495542572-74c82f60669c9db27cad113d22379c72.jpg ";
NSCharacterSet *set = [NSCharacterSet URLQueryAllowedCharacterSet];
NSString *endcodedString = [urlofimage stringByAddingPercentEncodingWithAllowedCharacters:set];
NSLog(#"%#", [NSURL URLWithString:endcodedString]);
EDIT:
The encoding highlighted, that there are invalid characters at the end of the URL. Lets get rid of them with the following code:
NSString * urlofimage = #"https://www.radioevros.gr/wp-content/uploads/2017/05/1495542572-74c82f60669c9db27cad113d22379c72.jpg ";
NSString *trimmedString = [urlofimage stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(#"%#", [NSURL URLWithString:trimmedString]);

UIImage does not download URLs, even though it recognizes the correct amount it should download

I'm having a weird string / array problem. When I count the # of objects in the array (values taken using [string description], it returns two, the correct amount of objects. When I try and download the image, it the UIImage does not display anything.
Here's the log of the URLs, from the array photoArg (if you try and go them it will say they are invalid, as I changed a few lines)
(
"\n\"https://scontent-a.xx.fbcdn.net/hphotos-ash2/s720x720/196148_2542310658202194_959795763_n.jpg\"",
"\n\"https://fbcdn-sphotos-c-a.akamaihd.net/hphotos-ak-ash3/s720x720/576808_2239914766108450_770925407_n.jpg\"\n"
)
Here's my numberOfItemsInSection:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [self.photoArg count];
}
My cellForItemAtIndexPath:
- (TBCollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CollectionViewCell";
TBCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
NSString *ImageURL = [self.photoArg objectAtIndex:indexPath.item];
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:ImageURL]];
[cell.imageView setImage:[UIImage imageWithData:imageData]];
return cell;
}
My TBCollectionViewCell is just a standard UICollectionViewCell, except with a UIImageView inside of it.
I'm thinking that the reason the URLs will not download in the cellForItemAtIndexPath: method is that they are not formatted properly. if that is the case, than how should I properly format the array data?
That's because your strings aren't valid URL's. You'll want to strip out the \n\" and the \" in order for dataWithContentsOfURL: do receive valid data.
"\n\"https://scontent-a.xx.fbcdn.net/hphotos-ash2/s720x720/196148_2542310658202194_959795763_n.jpg\"",
It isn't really pretty, but this should work just find for you.
NSString *string = #"\n\"https://scontent-a.xx.fbcdn.net/hphotos-ash2/s720x720/196148_2542310658202194_959795763_n.jpg\"";
NSString *noNewLines = [string stringByReplacingOccurrencesOfString:#"\n" withString:#""];
NSString *noEscapes = [noNewLines stringByReplacingOccurrencesOfString:#"\"" withString:#""];
NSURL *validURL = [NSURL URLWithString:noEscapes];

Convert Byte Data to image from XML Parsing

I want to convert this byte data to fetch an image from it.
i have used this base64Encoding method but this does not seem to be useful.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *base64StringEncoder = #"data:image/png;base64,";
base64StringEncoder = [base64StringEncoder stringByAppendingString:[[parserDataContentArray objectAtIndex:indexPath.row] exhibitorByteImageObjectClass]];
NSURL *profilePicURL = [NSURL URLWithString:base64StringEncoder];
NSData *profilePicimageData = [NSData dataWithContentsOfURL:profilePicURL];
if (profilePicimageData.length!=0) {
cell.exhibitorImage.image = [UIImage imageWithData:profilePicimageData];
}
return cell;
}
where parserDataContentArray is the mutable Array holding parsed Data.
and exhibitorByteImageObjectClass is the NSString property on which i am setting the node after checking particular tag exist.
XML Looks like
<PRODUCTION_B_IMAGE>
iVBORw0KGgoAAAANSUhEUgAAAKAAAACPCAYAAAB9NdDOAAAKQ2lDQ1BJQ0MgUHJvZmlsZQAASA2dlndUU1kTwO97L73QEkKREnoNTUoAkRJ6kV5FJSQBQgkYErBXRAVXFBVpig==
</PRODUCTION_B_IMAGE>
Please download this : NSData+Base64 files
dataWithContentsOfURL doen't actually take data from the URL but from the resource that is located at the URL. This is one of the easiest wrappers to use (decode and encode) base64 strings.
You have your NSString with base64 data in [parserDataContentArray objectAtIndex:indexPath.row] I believe. So try this :
NSData *tempData = [NSData dataFromBase64String:[parserDataContentArray objectAtIndex:indexPath.row]];
if (tempData.length!=0) {
cell.exhibitorImage.image = [UIImage tempData];
}

TableView cells are being slow when scrolling

I have a tableView which shows a list of Facebook friends. I have an imageview within the cell which displays the profilePicture of the user. Using AFNetworking I call the new image and put a placeholder whilst loading.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"FbFriendCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
if (tableView == self.searchDisplayController.searchResultsTableView) {
NSDictionary *friend = (NSDictionary *)[self.searchResults objectAtIndex:indexPath.row];
cell.textLabel.text = [friend valueForKey:#"name"];
} else {
NSDictionary *friend = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:10];
UILabel *displayName = (UILabel *)[cell.contentView viewWithTag:20];
UIButton *playButton = (UIButton *)[cell.contentView viewWithTag:30];
displayName.text = [friend valueForKey:#"name"];
UIImage *defaultPhoto = [UIImage imageNamed:#"person.png"];
NSString *urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture", friend[#"id"]];
NSURL *avatarUrl = [NSURL URLWithString:urlString];
[profilePic setImageWithURL:avatarUrl placeholderImage:defaultPhoto];
profilePic.contentMode = UIViewContentModeScaleAspectFit;
}
This is causing some speed/performance issues for the tableview. Does anyone know why this would be, is this setup correctly?
The cells are prototype cells created with a storyboard. I also have other code for the other objects in the cell, but removing the profile Picture section makes the cell perform normally so this appears to be the issue, just not sure why.
EDIT
UIImage *defaultPhoto = [UIImage imageNamed:#"person40x40.png"];
NSString *urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?width=40&height=40", friend[#"id"]];
I have updated the pictures to fit the 40x40 image view but no difference. The iphone4 is slow to load the table cells. Compared to an iphone5 which is extremely smooth in scrolling.
Here is the heaviest in Time Profiler:
Looks like profilePic is the worst. This is because of the Data request from Facebook. I have changed the profilePic to only be the default Pic which is not a URL request and the table view is fine. So this is clearly an issue with performance for the setImageWithURL.
Looking at other questions it appears to be the best way to accomplish this though :- Best practices for managing facebook friends pics in iOS App
Any thoughts welcome
Auto-layout can cause some issues. Also, if you are resizing the images as they come in, that can cause slowness. The easiest way to tell for sure is to run Time Profiler (with Hide System Libraries and Show Obj-C Only checked). This will tell you where your slowness is coming from.
I now have few idea to improve your performance problem.
1) Requesting your friend improvment
From your edit it look like requestion your friend also take a fair amount of time:
NSDictionary *friend = [[self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)] objectAtIndex:indexPath.section]] objectAtIndex:indexPath.row];
I'm sure you can cache most of this call with something like:
-(void)viewDidLoad{
[super viewDidLoad];
this.friendsInsensitive = [self.sections valueForKey:[[[self.sections allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
}
2) Web request improvement 1/2
reading few post about NSURLConnection and the event loop and blocking the main thread with async call
Let try something. Call the image web request in an other thread.
[...]
UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:10];
UILabel *displayName = (UILabel *)[cell.contentView viewWithTag:20];
UIButton *playButton = (UIButton *)[cell.contentView viewWithTag:30];
displayName.text = [friend valueForKey:#"name"];
UpdateImgContainter *containter = [UpdateImgContainter alloc] initWithCell:cell andFriendId:friend[#"id"];
[self performSelectorInBackground:#selector(requestImg:) withObject:containter];
}
-(void)requestImg:(UpdateImgContainter *)containter{
UIImage *defaultPhoto = [UIImage imageNamed:#"person.png"];
NSString *urlString = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture", containter.friendId];
NSURL *avatarUrl = [NSURL URLWithString:urlString];
[profilePic setImageWithURL:avatarUrl placeholderImage:defaultPhoto]; //warning it's not good practice to upload the UI from an other thread than MainThread
profilePic.contentMode = UIViewContentModeScaleAspectFit;
}
2) Web request improvement 2/2
I just find out an other way to do it. And it's probably more reliable.
Download this LazyTableImages project from Apple itself. It was create exactly to teach the probleme you are facing.
At the end of the day I just think setImageWithURL: is maybe not that quick (?) and the point N°1 was probably part of your problem too. Looking a LazyTableImages project Apple simply use a NSURLConnection.

iOS Split view controller - changing image in detailViewController

This is another of those "I'm sure there's an easy answer to this" questions, but I find myself baffled.
I'm using the split view controller from the template. I'm successfully passing a NSString to the _detailItem variable, but am unable to use it to create and load an image into an UIImageView (named "stripImage").
It works up until:
[self.stripImage setImage:[UIImage imageNamed: _detailItem]];
If I put a string literal into the same line of code (like #"image20.jpg"), it works fine.
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
NSLog(#"_detailItem is still: %#",_detailItem);
// correctly reports the name of the imagefile (for example: "image20.jpg"
[self.stripImage setImage:[UIImage imageNamed: _detailItem]];
NSLog(#"The image being shown is: %#",self.stripImage.image);
//returns "The image being shown is: (null)"
}
}
Please help keep my head from exploding. Thanks in advance.
... and I've tried it this way:
(in my Master view controller):
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Selected row %i",[indexPath row]);
NSString *imageName = [[stories objectAtIndex:[indexPath row]] objectForKey:#"link"];
NSLog(#"The image is: %#", imageName);
// These two work, oddly enough...
self.detailViewController.detailTitle.text = [[stories objectAtIndex:[indexPath row]]
objectForKey:#"title"];
self.detailViewController.detailSubtitle.text = [[stories objectAtIndex:[indexPath row]]
objectForKey:#"subtitle"];
// this one, not so much...
[self.detailViewController loadUpImageWith:imageName];
}
and in my Detail view controller:
- (void)loadUpImageWith:(NSString *)what
{
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:[NSString
stringWithFormat:#"strips/%#", what]];
NSLog(#"The file's url is: %#",path);
UIImage *img = [UIImage imageWithContentsOfFile:path];
NSLog(#"The resultant image is: %#",img);
stripImage.image = img;
}
But here's the weird thing... If I replace the variable ("what" in this case) with a string literal:
NSString *path = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:[NSString
stringWithFormat:#"strips/%#", #"grumbles300.jpg"]];
... it works, displaying that one image. But I want to be able to use a variable there!!
Help me Obiwan Kenobi! You're my only hope.
Embarrassing operator error.
I was adding a buncha images to the bundle, but it apparently kept track of the folder that contained them, which needed to be added to the file name. I thought UIImage imageNamed: would track down the images, as long as they were contained in the main bundle. Apparently not.
Perhaps this would be useful to someone who's experiencing the same sort of brain fart.
After resolving this, it was easy to do this:
- (void)loadupDetailTitle:(NSString *)title
subtitle:(NSString *)subtitle
image:(NSString *)imageName
{
NSString *path = [#"strips/" stringByAppendingPathComponent:imageName];
stripImage.image = [UIImage imageNamed:path];
detailTitle.text = title;
detailSubtitle.text = subtitle;
}

Resources