Challenge: More Data


#1

This was fairly simple, with the most complex part being setting up the UITableViewCell subclass. My header/implementation files for this class are below:

[code]#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface NerdfeedItemCell : UITableViewCell {
UILabel *titleLabel;
UILabel *categoryLabel;
UILabel *authorLabel;
}

@property (nonatomic, retain) UILabel *titleLabel;
@property (nonatomic, retain) UILabel *categoryLabel;
@property (nonatomic, retain) UILabel *authorLabel;

  • (void)setFeed;

@end[/code]

[code]#import “NerdfeedItemCell.h”

@implementation NerdfeedItemCell

@synthesize titleLabel, categoryLabel, authorLabel;

  • (id)initWithStyle:(UITableViewCellStyle)style
    reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style
    reuseIdentifier:reuseIdentifier];

    if (self) {
    titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
    [[self contentView] addSubview:titleLabel];

      authorLabel = [[UILabel alloc] initWithFrame:CGRectZero];
      [[self contentView] addSubview:authorLabel];
      
      categoryLabel = [[UILabel alloc] initWithFrame:CGRectZero];
      [[self contentView] addSubview:categoryLabel];
    

    }

    return self;
    }

  • (void)layoutSubviews {
    [super layoutSubviews];

    // Spacing between borders
    float spacing = 5.0;

    // Get amount of space we have to work with
    CGRect bounds = [[self contentView] bounds];

    float h = bounds.size.height;
    float w = bounds.size.width;

    // Create left-most rectangle for Category Label
    CGRect categoryFrame = CGRectMake(spacing, spacing, w/3.0, h/2.0);
    [categoryLabel setFrame:categoryFrame];

    // Create the middle rectangle for the Author Label
    CGRect authorFrame = CGRectMake(categoryFrame.size.width + categoryFrame.origin.x + spacing, spacing, w/3.0, h/2.0);
    [authorLabel setFrame:authorFrame];

    // Create the right-most rectangle for Title Label
    CGRect titleFrame = CGRectMake(authorFrame.size.width + authorFrame.origin.x + spacing, spacing, w/3.0, h/2.0);
    [titleLabel setFrame:titleFrame];
    }

  • (void)setFeed {
    [categoryLabel setText:@“Category”];

    [authorLabel setText:@“Author”];

    [titleLabel setText:@“Title”];
    }

@end[/code]

The setFeed method was more or less a stub method for me to see if my custom cell was even being created and displaying properly. The math used to create the size of the rects for the contentView isn’t as elegant as the math used in the Subclassing UITableViewCell chapter, but it worked for my purposes. After this class was created, I made updates to RSSItem as such:

[code]#import <Foundation/Foundation.h>

@interface RSSItem : NSObject {
NSString *title;
NSString *link;
NSMutableString *currentString;

id parentParserDelegate;

// CHALLENGE
NSString *author;
NSString *category;

}

@property (nonatomic, assign) id parentParserDelegate;

@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *link;

// CHALLENGE
@property (nonatomic, retain) NSString *category;
@property (nonatomic, retain) NSString *author;

@end[/code]

In the implementation file, I only had to made updates to one method:

[code]- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qualifiedName
attributes:(NSDictionary *)attributeDict {

NSLog(@"\t\t%@ found a %@ element", self, elementName);

if ([elementName isEqual:@"title"]) {
    currentString = [[NSMutableString alloc] init];
    [self setTitle:currentString];
}
else if ([elementName isEqual:@"link"]) {
    currentString = [[NSMutableString alloc] init];
    [self setLink:currentString];
}
// CHALLENGE
else if ([elementName isEqual:@"category"]) {
    currentString = [[NSMutableString alloc] init];
    [self setCategory:currentString];
}
else if ([elementName isEqual:@"author"]) {
    currentString = [[NSMutableString alloc] init];
    [self setAuthor:currentString];
}

}[/code]

Finally, I made updates to my ListViewController implementation file to call the new cell subclass. Again, only one method needed updating:

[code]- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

NerdfeedItemCell *cell = (NerdfeedItemCell *)[tableView dequeueReusableCellWithIdentifier:@"NerdfeedItemCell"];

if (cell == nil) {
    cell = [[[NerdfeedItemCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                   reuseIdentifier:@"NerdfeedItemCell"] autorelease];
}

RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];

// Using properties, set each label
cell.titleLabel.text = [item title];
cell.categoryLabel.text = [item category];
cell.authorLabel.text = [item author];


return cell;

}[/code]

And that’s it! However, all of my Author values were the same "no_email@example.com". Not sure if anyone else has solved this and gotten the same result, but since my Category and Title were coming in correctly, I assume I am getting the correct Author, as well.


#2

I got the same thing. I noticed that the name of the authors can be found inside the title labels, though.
For example:
The first cell that pops up has

the title: "Big Nerd Ranch General Discussions :: testing :: Author Joe Conway"
the category: “Big Nerd Ranch General Discussions"
and the author "no_email@example.com

So instead of getting the author label from the parser, you could probably extract it from currentString under the if ([elementName isEqual:@“title”]) condition by searching for the characters “author” or “reply by” within the currentString.
Then you could just call [self setAuthor:] using that extraction as the argument.

I just can’t figure out how to extract the string given a set of characters to look for.

Any ideas?


#3

hi,

I extracted the author name from the 'no_email@example.com (authorname)’ string.

// remove "no_email@example.com (" and closing ")" int loc = [@"no_email@example.com (" length]; NSRange r = NSMakeRange(loc, [[item author] length] - loc - 1); NSString *author = [[item author] substringWithRange:r];