Gold Challenge: Solution #2


#1

Here’s my second attempt at this challenge. I moved the title manipulation into the RSSItem implementation. This eliminated a lot of the looping. It allowed me to put the item directly into the correct thread or start a new one. It does this when it finds the end of an item element. You’ll see a few things I added using the new class RSSThread. Basically, an Item is a single post. A group of related posts is a thread, and all of the thread from the channel are put into the theFeed. The number of child posts is just used to determine the number of rows - just playing around really. I like this code much better than the previous primarily because it avoids all of the item parsing.

RSSItem.m

#import "RSSItem.h"
#import "RSSThread.h"

@implementation RSSItem

@synthesize parentParserDelegate, title, link, pubDateString, pubDate, currentFeed;

-(void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
 namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
   attributes:(NSDictionary *)attributeDict
{
//    NSLog(@"t\t\%@ found a %@ element", self, elementName);
    
    if ([elementName isEqualToString:@"title"])
    {
        currentString = [[NSMutableString alloc] init];
        [self setTitle:currentString];
    }
    else if ([elementName isEqualToString:@"link"])
    {
        currentString = [[NSMutableString alloc] init];
        [self setLink:currentString];
    }
    else if ([elementName isEqualToString:@"pubDate"])
    {
        currentString = [[NSMutableString alloc] init];
        [self setPubDateString:currentString];
    }
    
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    [currentString appendString:string];
}

-(void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
 namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
    currentString = nil;
    
    if ([elementName isEqualToString:@"item"])
    {
        [self putPostIntoRSSThreadAndFeed];
        
        [parser setDelegate:parentParserDelegate];
    }
}

-(void)putPostIntoRSSThreadAndFeed
{
    //Lets first trim the titles so they are just the titles. Maybe pull out the Chapter later
    NSRegularExpression *titleReg = [[NSRegularExpression alloc] initWithPattern:@"(.*) :: (.*) :: .*"
                                                                         options:0
                                                                           error:nil];
    
    NSString *postTitle = [self title];
    NSArray *matches = [titleReg matchesInString:postTitle options:0 range:NSMakeRange(0,[postTitle length])];
    if ([matches count] > 0)
    {
        NSTextCheckingResult *result = [matches objectAtIndex:0]; //This is all three groups
        NSString *newPostTitle = [postTitle substringWithRange:[result rangeAtIndex:2]];
        [self setTitle:newPostTitle];
    }
    else
    {
        //If the title is too long the third section is truncated by the server and replaced with ...
        //This fixes that and removes the ...
        //However, the title will not be truly correct, so we'll have to make up for that later
        NSRegularExpression *titleReg2 = [[NSRegularExpression alloc] initWithPattern:@"(.*) :: (.*) ... .*"
                                                                              options:0
                                                                                error:nil];
        NSArray *match2 = [titleReg2 matchesInString:postTitle options:0 range:NSMakeRange(0, [postTitle length])];
        if ([match2 count] > 0)
        {
            NSTextCheckingResult *result = [match2 objectAtIndex:0]; //This is all three groups
            NSString *newPostTitle = [postTitle substringWithRange:[result rangeAtIndex:2]];
            [self setTitle:newPostTitle];
        }
    }
    
    [self setThreadForPost];
}

-(void)setThreadForPost
{
    BOOL threadSet = NO;
    NSString *currentTitle = [self title];
    NSLog(@"Link: %@", [self link]);
    for (RSSThread *thread in currentFeed)
    {
        NSString *threadTitle = [thread title];
        
        if ([currentTitle isEqualToString:threadTitle])
        {
            [thread addPost:self];
            threadSet = YES;
            break;
        }
    }
    
    if (!threadSet)
    {
        RSSThread *newThread = [[RSSThread alloc] initWithPost:self];
        [currentFeed addObject:newThread];
    }
}

@end

RSSThread.h

#import <Foundation/Foundation.h>
@class RSSItem;

@interface RSSThread : NSObject

@property (nonatomic, strong)NSString *title;
@property (nonatomic)int numberOfPosts;
@property (nonatomic, strong)NSMutableArray *thread;

-(id)initWithPost:(RSSItem *)post;
-(void)addPost:(RSSItem *)post;

@end

RSSThread.m

#import "RSSThread.h"
#import "RSSItem.h"

@implementation RSSThread

@synthesize title, numberOfPosts, thread;

-(id)initWithPost:(RSSItem *)post
{
    self = [super init];
    
    [self setTitle:[post title]];
    [self setNumberOfPosts:1];
    
    thread = [[NSMutableArray alloc] initWithObjects:post, nil];
    
    return self;
    
}

-(void)addPost:(RSSItem *)post
{
    [thread addObject:post];
    [self setNumberOfPosts:[self numberOfPosts] +1];
}

@end

RSSChannel.m

#import "RSSThread.h"
#import "RSSItem.h"

@implementation RSSThread

@synthesize title, numberOfPosts, thread;

-(id)initWithPost:(RSSItem *)post
{
    self = [super init];
    
    [self setTitle:[post title]];
    [self setNumberOfPosts:1];
    
    thread = [[NSMutableArray alloc] initWithObjects:post, nil];
    
    return self;
    
}

-(void)addPost:(RSSItem *)post
{
    [thread addObject:post];
    [self setNumberOfPosts:[self numberOfPosts] +1];
}

@end