Saturday 3 November 2012

Tweet Using XML Parsing


his is a tutorial on parsing XML data in your iPhone app. I won’t be explaining things in great detail here because I assume if you are doing XML parsing you have some experience and don’t need to be shown a lot of the basics. At this point you most likely just want to see some code and implement it into your own app. If you have any questions feel free to ask.
Final App Shot

What we will be doing here is calling my Twitter account through a URL and receiving an XML of my status tweets. We’ll then parse that XML and show the tweets in a table view. This really isn’t much different than the way a Web Service will work. We are calling a URL and then receiving some data back. In this case it is Twitter that has done the web service part for us on their servers and they are kind enough to return our data in an XML format. We could be calling a Web Service that we have written on one of our own servers and then parsing the returned XML.
Anyway, here we go.
1.) Create a new Navigation-based Application named XMLParserTutorial. We will be displaying our parsed data in the UITableView.
2.) We need to create a class to hold the individual data after it’s parsed. In this case the data will be a tweet. So we will create a class named Tweet. Right click on Classes, select Add > New File … and choose Objective-C class (Subclass of NSObject) click Next and name it Tweet.
3.) Open up our Tweet header file (Tweet.h) and add two NSStrings. One for the tweet’s actual content and one for the date it was created.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <foundation foundation.h="">
@interface Tweet : NSObject
{
    NSString     *content;
    NSString     *dateCreated;
     
}
@property (nonatomic, retain) NSString   *content;
@property (nonatomic, retain) NSString   *dateCreated;
@end
</foundation>
4.) Next open up the implementation file Tweet.m and synthesize our variables we just created.
?
1
2
3
4
5
6
7
8
#import "Tweet.h"
@implementation Tweet
@synthesize content, dateCreated;
@end
5.) We need to create our XMLParser object. Right click on Classes, select Add > New File … and choose Objective-C class (Subclass of NSObject) click next and name it XMLParser.
6.) Open up XMLParser.h. Import Tweet.h and implement the NSXMLParserDelegate protocol.
?
1
2
3
4
5
6
#import <foundation foundation.h="">
#import "Tweet.h"
@interface XMLParser : NSObject <nsxmlparserdelegate>
</nsxmlparserdelegate></foundation>
Declare variables for an NSMutableString, NSMutableArray, NSXMLParser and Tweet. Then set the properties for our tweets array and define a loadXMLByURL action.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#import <foundation foundation.h="">
#import "Tweet.h"
@interface XMLParser : NSObject <nsxmlparserdelegate>
{
    NSMutableString *currentNodeContent;
    NSMutableArray  *tweets;
    NSXMLParser     *parser;
    Tweet           *currentTweet;
     
}
@property (readonly, retain) NSMutableArray *tweets;
-(id) loadXMLByURL:(NSString *)urlString;
@end
</nsxmlparserdelegate></foundation>
7.) Open up XMLParser.m. Import our Tweet.h file, synthesize the tweets array and implement our loadXMLByURL action.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import "XMLParser.h"
#import "Tweet.h"
@implementation XMLParser
@synthesize tweets;
-(id) loadXMLByURL:(NSString *)urlString
{
    tweets          = [[NSMutableArray alloc] init];
    NSURL *url      = [NSURL URLWithString:urlString];
    NSData  *data   = [[NSData alloc] initWithContentsOfURL:url];
    parser          = [[NSXMLParser alloc] initWithData:data];
    parser.delegate = self;
    [parser parse];
    return self;
}
We need to release the parser object we created so I am going to do that in a dealloc method that we’ll implement.
?
1
2
3
4
5
- (void) dealloc
{
    [parser release];
    [super dealloc];
}
8.) There are three methods we need to implement that follow the NSXMLParserDelegate protocol. They are parser:didStartElement:namespaceURI:qualifiedName:attributes, parser:didEndElement:namespaceURI:qualifiedName and parser:foundCharacters.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    if ([elementname isEqualToString:@"status"])
    {
        currentTweet = [Tweet alloc];
    }
}
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    if ([elementname isEqualToString:@"text"])
    {
        currentTweet.content = currentNodeContent;
    }
    if ([elementname isEqualToString:@"created_at"])
    {
        currentTweet.dateCreated = currentNodeContent;
    }
    if ([elementname isEqualToString:@"status"])
    {
        [tweets addObject:currentTweet];
        [currentTweet release];
        currentTweet = nil;
        [currentNodeContent release];
        currentNodeContent = nil;
    }
}
- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    currentNodeContent = (NSMutableString *) [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
I know the element name we are looking for because I have taken a peek at the XML that we will be parsing. If we were parsing a different XML we would need to know the names of the nodes in that XML we wanted to parse.
9.) Open up RootViewController.h. Import XMLParser.h and add our XMLParser and a UIImageView. The UIImageView is really just for cosmetics.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import <uikit uikit.h="">
#import "XMLParser.h"
@interface RootViewController : UITableViewController
{
    XMLParser *xmlParser;
     
    UIImageView *customImage;
}
@property (nonatomic, retain) UIImageView *customImage;
@end
</uikit>
10.) Now open up the implementation file (RootViewController.m). We need to import our Tweet.h file and synthesize our variable. Then in our viewDidLoad method we are going to access my twitter status tweets as XML and load it into our XML Parser. And just because I like to keep things aesthetically pleasing, we’ll set the title to “Tweets”.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import "RootViewController.h"
#import "Tweet.h"
@implementation RootViewController
@synthesize customImage;
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad
{
     
    xmlParser = [[XMLParser alloc] loadXMLByURL:@"http://api.twitter.com/1/statuses/user_timeline/KentFranks.xml"];
     
     
    [super viewDidLoad];
     
    self.title = @"Tweets";
     
}
11.) Let’s set up our table to display the tweets. I’ve set the number of sections to 1.
?
1
2
3
4
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
12.) I’m using the tweets array to set the number of rows in the sections.
?
1
2
3
4
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[xmlParser tweets] count];
}
13.) And then all the real work will get done in the tableView:cellForRowAtIndexPath method.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
     
    static NSString *CellIdentifier = @"Cell";
     
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }
     
    UIImage  *twitterLogo = [[UIImage imageNamed:@"twitter-logo.png"]autorelease];
     
    Tweet *currentTweet = [[xmlParser tweets] objectAtIndex:indexPath.row];
     
    CGRect imageFrame = CGRectMake(2, 8, 40, 40);
    self.customImage = [[[UIImageView alloc] initWithFrame:imageFrame] autorelease];
    self.customImage.image = twitterLogo;
    [cell.contentView addSubview:self.customImage];
     
    CGRect contentFrame = CGRectMake(45, 2, 265, 30);
    UILabel *contentLabel = [[[UILabel alloc] initWithFrame:contentFrame] autorelease];
    contentLabel.numberOfLines = 2;
    contentLabel.font = [UIFont boldSystemFontOfSize:12];
    contentLabel.text = [currentTweet content];
    [cell.contentView addSubview:contentLabel];
     
    CGRect dateFrame = CGRectMake(45, 40, 265, 10);
    UILabel *dateLabel = [[[UILabel alloc] initWithFrame:dateFrame] autorelease];
    dateLabel.font = [UIFont systemFontOfSize:10];
    dateLabel.text = [currentTweet dateCreated];
    [cell.contentView addSubview:dateLabel];
     
     
     
    return cell;
}
We are setting the current tweet to the object in our tweets array that matches indexPath.row.
?
1
Tweet *currentTweet = [[xmlParser tweets] objectAtIndex:indexPath.row];
Most of the rest of the code in here is just customizing the look of our cells. I’m not explaining this in detail because I’m assuming if you are mostly interested in parsing the XML. If you want to know more about customizing the table view cells you can take a look at the tutorial.
I have included one graphic in the display that you will need to add to your project “twitter-logo.png”. You can download the graphic from here, and then just right click on Resources and select Add > Existing Files … navigate to where you downloaded the file, then choose to copy the file into your project.
14.) The only other thing I’ve done here is set the height of our rows in the tableView:heightForRowAtIndexPath method. And the release our xmlParser object in dealloc.
?
1
2
3
4
5
6
7
8
9
10
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 55;
}
- (void)dealloc
{
    [xmlParser release];
    [super dealloc];
}
That’s all there is to it. Make sure everything is saved, click Build and Run.
Simulator Shot

Link--http://www.theappcodeblog.com/2011/05/09/parsing-xml-in-an-iphone-app-tutorial/

1 comment:

  1. Are you trying to earn cash from your traffic with popup ads?
    In case you do, have you tried using PopCash?

    ReplyDelete