TableView cells are being slow when scrolling - ios

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.

Related

JSON File Not Loading until UITableView

In order to test my App I have created a JSON file that I am drawing fake values from, however in my table View I want to exclude the user's data. In order to load this file I have used this code:
//create a new JSONLoader with a local file from URL
JSONLoader *jsonLoader = [[JSONLoader alloc] init];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"chatters" withExtension:#"json"];
//load the data on a background queue
//use for when connecting a real URL
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_localChatters = [jsonLoader chattersFromJSONFile:url];
//push data on main thread (reload table view once JSON has arrived)
//[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
});
Then I load it into a tableView with no problems:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"PopulationCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Chatter *chatter = [_localChatters objectAtIndex:indexPath.row];
NSData *fbImageData = [NSData dataWithContentsOfURL:[NSURL URLWithString: chatter.url]];
UIImage *profilePicture = [UIImage imageWithData:fbImageData];
cell.imageView.image =profilePicture;
[cell.textLabel setAdjustsFontSizeToFitWidth: NO];
cell.textLabel.text = [NSString stringWithFormat:#"%# joined at %#",chatter.name,chatter.joined];
cell.textLabel.textColor = [UIColor grayColor];
return cell;
}
However this includes the user information as well, which is something we don't want. In order to get around this problem I have created a separate method that would in theory create a second mutable array with just the data excluding the user's:
- (void)getData{
NSLog(#"%#",_localChatters);
NSMutableArray *newArray = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i<[_localChatters count]; i++) {
Chatter *newChatter = [_localChatters objectAtIndex:i];
if ([newChatter.facebookID isEqualToString:_loggedInFBID]) {
} else {
[newArray addObject:newChatter];
};
}
NSLog(#"%#",newArray);
}
However when this method is called from the view did load with a
[self getData]
the _localChatters NSLogs as (null) and I believe subsequently the newArray is never filled and NSLogs as empty (). It is strange because when I log the _localChatters in the uitableview it is not null and of course all of the data is there when it loads. I'm at a loss why the _localChatters would read as null in this method when I am fairly certain the array loads just fine from the dispatch_async request.
EDIT:
Here is a small sample of JSON, I've removed some of the personal information such as FB ID and picture URL, however all of the objects are the same.
"name": "Johnny",
"room": "London",
"latitude": 41.414483,
"longitude": 2.152579,
"message": "I agree, I think I'm going there right now",
"timestamp": "9:23 PM",
"url": " <<actual FB profile URL>>",
"facebookID":"<<personal FB ID >>",
"joined":"12:13 AM",
The problem is multithreading. _localChatters array is created asynchronously so in most cases this will happen after viewDidLoad. You could move [self getData] to dispatch_async block (before reloading table view and after fetching data from JSON).

Passing parameters makes the code run "slower"?

Background Information
Currently I'm setting the text for each UITableViewCell in my UITableView using the following code:
Scenario A:
cell.textLabel.attributedText = [news formattedSubject];
However, consider if I were to add a parameter for the formattedSubject definition, just a single integer parameter so the code is now:
Scenario B:
cell.textLabel.attributedText = [news formattedSubject:1];
The text in each table view cell is roughly 3-5 lines in length, and is read from an external source and parsed via JSON. Here's a diagram of the desired result, which is what happens in Scenario A:
Scenario A Flow Diagram:
Image A simply displays the default, empty UITableView that I get when the app is still loading the JSON data. After the app retrieves and parses this data, it then populates the data into the UITableView, which results in Image B. This is the desired (and expected) result.
However, if I add a parameter to formattedSubject, I instead get the flow diagram below:
Scenario B Flow Diagram:
Once again, Image A displays the default UITableView. However, it is what happens in Image B that is the problem. In Image B, the data has been parsed, but has not yet been formatted properly by formattedSubject, thus resulting in a single, horizontally-narrow, and lengthy row of unformatted text. After a fraction of a second, the app looks like Image C, the end result which displays the formatted data after it has been parsed.
My question:
The only change I made is the addition of a parameter to formattedSubject. That is, I changed -(NSAttributedString*)formattedSubject { to -(NSAttributedString*)formattedSubject:(int)state {. It doesn't matter that there is nothing within formattedSubject that actually uses the state integer, I'm still getting the results from Scenario B.
This change seems to make the code run more slowly. It creates a delay between when the data is parsed and when it is formatted and displayed in the UITableView. I'm curious as to why this is, and how I can fix/circumvent this issue.
Aside from being an aesthetics issue, what happens in Scenario B also interferes with my automatic loading of new data when the user reaches the end of the UITableView. Because of horizontally-narrowed rows of text, the last row of data will momentarily be displayed in the UITableView when it is first loaded, thus causing data to be retrieved twice upon app startup.
I am nowhere close to an expert in coding, and thus it makes absolutely no sense to me how simply adding a parameter to my NSAttributedString could create the aforementioned delay. I would be very appreciative if someone could:
Explain why this is happening, and
Offer a solution to resolve this issue.
Thank you very much for reading this, any and all comments/help is welcomed.
Edit 1: #Vijay-Apple-Dev.blogspot.com, #txulu
Here is my formattedSubject code:
-(NSAttributedString*)formattedSubject:(int)state {
if(formattedSubject!=nil) return formattedSubject;
NSDictionary *boldStyle = [[NSDictionary alloc] init];
if(state==1) {
boldStyle = #{NSFontAttributeName:[UIFont fontWithName:#"Helvetica-Bold" size:16.0],NSForegroundColorAttributeName:[UIColor colorWithRed:0.067 green:0.129 blue:0.216 alpha:1.0]};
}
else {
boldStyle = #{NSFontAttributeName:[UIFont fontWithName:#"Helvetica-Bold" size:16.0],NSForegroundColorAttributeName:[UIColor whiteColor]};
}
NSDictionary* normalStyle = #{NSFontAttributeName: [UIFont fontWithName:#"Helvetica" size:14.0]};
NSMutableAttributedString* articleAbstract = [[NSMutableAttributedString alloc] initWithString:subject];
[articleAbstract setAttributes:boldStyle range:NSMakeRange(0, subject.length)];
[articleAbstract appendAttributedString:[[NSAttributedString alloc] initWithString:#"\n"]];
int startIndex = [articleAbstract length];
NSTimeInterval _interval=[datestamp doubleValue];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:_interval];
NSDateFormatter *_formatter=[[NSDateFormatter alloc]init];
[_formatter setDateFormat:#"MM/dd/yy"];
NSString* description = [NSString stringWithFormat:#"By %# on %#",author,[_formatter stringFromDate:date]];
[articleAbstract appendAttributedString:[[NSAttributedString alloc] initWithString: description]];
[articleAbstract setAttributes:normalStyle range:NSMakeRange(startIndex, articleAbstract.length - startIndex)];
formattedSubject = articleAbstract;
return formattedSubject;
}
Please note that as I said before, even if I don't actually use the state parameter, I still get the same results.
Here is my cellForRowAtIndexPath code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
News *news = newsArray[indexPath.row];
NSIndexPath *selectedIndexPath = [tableView indexPathForSelectedRow];
if([selectedIndexPath isEqual:indexPath]) {
cell.textLabel.attributedText = [news formattedSubject:1];
}
else {
cell.textLabel.attributedText = [news formattedSubject:0];
}
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIView *selectedBackgroundViewForCell = [UIView new];
[selectedBackgroundViewForCell setBackgroundColor:[UIColor colorWithRed:0.169 green:0.322 blue:0.525 alpha:1.0]];
cell.selectedBackgroundView = selectedBackgroundViewForCell;
cell.textLabel.highlightedTextColor = [UIColor whiteColor];
if (indexPath.row == [newsArray count] - 1) {
[self parseJSON];
}
return cell;
}
Please let me know if I can post anything else that may help.
Edit 2:
I'm not exactly sure if there is a performance issue. Upon further testing, I am inclined to believe that in Scenario A, the app loads and formats the cell data before displaying it, while in Scenario B, the app loads the data, displays it in the UITableViewCell, and then formats it, which creates the problem I detailed above.
Some people have brought up the code in my parseJSON method, so I'm posting it here for reference. As you can see I do indeed implement multithreading in order to prevent the data loading from lagging the application.
-(void)parseJSON
{
loading.alpha = 1;
loading.image = [UIImage imageNamed:#"loading.png"];
activityIndicator.alpha = 1;
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(checkLoading) userInfo:nil repeats:YES];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
parseNumber = parseNumber + 1;
int offset = parseNumber*20-1;
NSString *URLString = [NSString stringWithFormat:#"http://feedurl.com/feed.php?offset=%d",offset];
NSURL *url=[NSURL URLWithString:URLString];
NSData *data=[NSData dataWithContentsOfURL:url];
NSError* error;
if(data!=nil) {
json = [NSJSONSerialization JSONObjectWithData:data options: NSJSONReadingMutableContainers error: &error];
for(NSDictionary *newsInfo in json) {
News *newsList = [[News alloc] init];
newsList.thread = newsInfo[#"thread"];
newsList.author = newsInfo[#"author"];
newsList.subject = newsInfo[#"subject"];
newsList.body= newsInfo[#"body"];
newsList.datestamp = newsInfo[#"datestamp"];
[jsonTemp addObject:newsList];
}
newsArray = jsonTemp;
}
dispatch_sync(dispatch_get_main_queue(), ^{
if(data!=nil) {
[newsTable reloadData];
}
else {
activityIndicator.alpha = 0;
loading.image = [UIImage imageNamed:#"error.png"];
[self startTimer];
}
});
});
}
Edit:
Okay, there's a difference when calling [news formattedSubject] instead of [news formattedSubject:1]. The first one is like doing news.formattedSubject, this is, access the formattedSubject property that returns the ivar immediately, pretty fast. The second one calls the more complex formattedSubject: method that executes the code you posted, slower.
Original:
Your code seems fine except for some minor details like:
NSDictionary *boldStyle = [[NSDictionary alloc] init];
not being necessary because you assign just afterwards:
boldStyle = #{NSFontAttributeName ...}
Also, what I guess could be causing your problem is:
if (indexPath.row == [newsArray count] - 1) {
[self parseJSON];
}
Calling this inside your cellForRowAtIndexPath: could be a severe performance problem. If this method does a lot of work and does not do it in a background it could cause the delays you mention. As a rule of thumb, you should never do network/data processing in the main thread (cellForRowAtIndexPath will always be called in that thread by the system).
You says like below
"The text in each table view cell is roughly 3-5 lines in length, and is read from an external source and parsed via JSON. Here's a diagram of the desired result, which is what happens in Scenario A:"
I assume that you are reading data from
1.Local Core data Database
or
2.Web server's database.
For case 1, you should use NSFetchedResultsController, follow up this tutorial
https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsController_Class/Reference/Reference.html
http://www.raywenderlich.com/999/core-data-tutorial-for-ios-how-to-use-nsfetchedresultscontroller
For case 2 you should do in background thread,and update it by Main thread in tableview, when it is available, follow up this tutorial
How to load JSON asynchronously (iOS)

How to efficiently load images in UITableView?

I have a UITableView that will contain a high number of images.
Each cell will have 5 images, that are loaded randomly from Parse.com.
My query code, right now, is in cellForRowAtIndexPath.
This causes a few issues:
1.) There's some lag/delay when scrolling the table.
2.) The images, now for some odd reason, are not showing in the proper location.
3.) The images reload/change every time the table is scrolled.
I'd like for the images to be "loaded" just once when on this UIView, in the correct place, and with smooth scrolling.
What's the best way to handle this?
Here's the code for how I am loading the images:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// set up the cell here
// query and display random images from parse.com
PFQuery * query = [PFUser query];
[query whereKey:#"category" equalTo:self.cell.label.text];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error)
{
NSLog(#"Error: %# %#", error, [error userInfo]);
}
else
{
for (int i = 0; i < objects.count; i++)
{
self.profilePicObject = [objects objectAtIndex:i];
int imgRandom = arc4random() % [objects count];
self.randomProfilePicObject = [objects objectAtIndex:imgRandom];
self.imageFile = [self.randomProfilePicObject objectForKey:#"imageFile"];
NSURL * imageFileURL = [[NSURL alloc] initWithString:self.imageFile.url];
NSData * imageData = [NSData dataWithContentsOfURL:imageFileURL];
UIImage * aImage = [[UIImage alloc] initWithData:imageData];
self.cell.profilePicOne.image = aImage;
}
}
return self.cell;
}
EDIT:
I'm using SDWebImage and the table now scrolls smoothly and images are displaying.
The new issue:
Images are loading in wrong cells.
I'm querying the table and matching the label text to the proper string in my Parse table and using that to display the proper image.
Initially, some images load in the correct cell and some do not.
When I scroll, images appear all over the place.
What's the best way to fix this?
Here is how I am setting up the cells:
static NSString * cellIdentifier = #"FilterSelectCell";
self.cell = (FilterSelectCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (self.cell == nil)
{
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:#"FilterSelectCell" owner:self options:nil];
self.cell = [nib objectAtIndex:0];
self.cell.profilePicOne.clipsToBounds = YES;
self.cell.profilePicOne.layer.cornerRadius = 20.0;
self.cell.profilePicTwo.clipsToBounds = YES;
self.cell.profilePicTwo.layer.cornerRadius = 20.0;
self.cell.profilePicThree.clipsToBounds = YES;
self.cell.profilePicThree.layer.cornerRadius = 20.0;
self.cell.profilePicFour.clipsToBounds = YES;
self.cell.profilePicFour.layer.cornerRadius = 20.0;
self.cell.profilePicFive.clipsToBounds = YES;
self.cell.profilePicFive.layer.cornerRadius = 20.0;
}
self.cell.label.text = [self.myArray objectAtIndex:indexPath.row];
The best solution would be to use an image caching system such as SDWebImage to prevent duplicate web queries for the same image. It is extremely easy to use and lets you use a placeholder loading image while downloading the image data from the URL. It also loads images asynchronously so your UI isn't blocked and it will release images from the cache before your application is overloaded. You simply load images like this and SDWebImage does the magic:
[self.cell.profilePicOne setImageWithURL:imageFileURL placeholderImage:[UIImage imageNamed:#"LOADING_IMAGE.png"]];
SDWebImage Repository
Lazy loading is the better solution for this take a look on the following discussion
Lazy loading UITableView with multiple images in each cell
Use Asynchronous image downloader with cache support with an UIImageView category.I have been using this for long time.Damn sure ur problem may overcome with this SDWebImage
You can checkout this utility APSmartStorage.
It supports downloading, memory and disk cache.

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

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.

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