Viblo CTF
0

iOS working with UITableView and NSXMLParser

Ở bài viết này chúng ta hãy cùng tìm hiểu cách viết 1 App dạng đơn giản để có thể đọc báo trên iOS thông qua RSS. App gồm 2 màn hình chính là màn hình list danh sách các tin và màn hình chi tiết view tin.

Phần xử lý chính của App ta cần sử dụng lớp NSXMLParser, lớp này chịu trách nhiệm phân tích nội dung của RSS trả về để lấy ra các thành phần cần thiết và hiển thị lên màn hình.

  • Đầu tiên ta mở XCode và chọn New Project, chọn loại là Master-Detail Application

  • Tiếp đó cần mở StoryBroad và thiết kế giao diện cho App như sau:

Như trên màn hình ta thấy gồm có:

  • Navigation Bar để di chuyển màn hình và back lại
  • 1 Table View để hiển thị danh sách các tin tức của báo
  • 1 Detailed View chứa 1 Web View để hiển thị nội dung của tin tức được chọn.

Bước tiếp theo cần tạo kết nối của TableView với phần code:

 @property (strong, nonatomic) IBOutlet UITableView *tableView;

Tiếp đó trong phần DetailView, ta cần kéo 1 control Web View vào và chỉnh sửa kích cỡ sao cho kín màn hình, đồng thời tạo kết nối Outlet với phần code:

Để truyền url được chọn từ màn hình TablView, ta cần tạo 1 biến url để lưu url được chọn:

#import <UIKit/UIKit.h>

@interface APPDetailViewController : UIViewController

@property (copy, nonatomic) NSString *url;
@property (strong, nonatomic) IBOutlet UIWebView *webView;

@end

Quay lại màn hình chính, để implement phần phân tích RSS ta mở file APPMasterViewController.m và khai báo các biến như sau:

@interface APPMasterViewController () {

    NSXMLParser *parser;
    NSMutableArray *feeds;
    NSMutableDictionary *item;
    NSMutableString *title;
    NSMutableString *link;
    NSString *element;

}
@end

Tiếp theo ta cần thử nghiệm với 1 link RSS, bạn có thể vào: http://vnexpress.net/rss để lấy 1 link rss của báo, ví dụ: http://vnexpress.net/rss/tin-moi-nhat.rss. Tất nhiên trên ứng dụng thực tế ta cần cho người dùng chọn chuyên mục và lấy link rss tương ứng.

Sửa lại code phần viewDidLoad để khởi tạo giá trị các biến như sau:

- (void)viewDidLoad {

    [super viewDidLoad];

    feeds = [[NSMutableArray alloc] init];
    NSURL *url = [NSURL URLWithString:@"http://vnexpress.net/rss/tin-moi-nhat.rss"];
    parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

    [parser setDelegate:self];
    [parser setShouldResolveExternalEntities:NO];
    [parser parse];

}

Tiếp đó ta implement các phần dataSource và delegate của TableView như mọi khi:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return feeds.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];
    return cell;
}

Lưu ý dòng này ta set tiêu đề cho cell, bạn có thể tùy biến để hiển thị thêm thông tin:

cell.textLabel.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];

Để implement phần phân tích XML của RSS ta cần implement: NSXMLParserDelegate

@interface ENTMasterViewController : UITableViewController <NSXMLParserDelegate>

Mỗi khi parser tìm thấy 1 element nó sẽ gọi đến hàm didStartElement vì vậy ta cần implement hàm này để kiểm tra element tìm thấy có phải là "item" không thì ta sẽ khởi tạo 1 số biến:

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

    element = elementName;

    if ([element isEqualToString:@"item"]) {

        item    = [[NSMutableDictionary alloc] init];
        title   = [[NSMutableString alloc] init];
        link    = [[NSMutableString alloc] init];

    }

}

Tiếp theo mỗi khi parse tìm thấy 1 character nó sẽ gọi đến hàm foundCharacters, vì vậy ta cần implement để append thêm chuỗi vào biến đã khởi tạo:

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {

    if ([element isEqualToString:@"title"]) {
        [title appendString:string];
    } else if ([element isEqualToString:@"link"]) {
        [link appendString:string];
    }

}

Tiếp đó khi parse duyệt tới cuối của element nó gọi tới hàm didEndElement, vì vậy ta cần implement để add object vào mảng feeds

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

    if ([elementName isEqualToString:@"item"]) {

        [item setObject:title forKey:@"title"];
        [item setObject:link forKey:@"link"];

        [feeds addObject:[item copy]];

    }

}

Khi tới cuối của RSS ta cần implement parserDidEndDocument để kết thúc việc phân tích RSS và reload lại TableView

- (void)parserDidEndDocument:(NSXMLParser *)parser {

    [self.tableView reloadData];

}

Như vậy chúng ta đã hoàn thành phần phân tích RSS và hiển thị lên VIEW chính, giờ ta chỉ cần implement phần Segue để truyền url được chọn sang phần Detailed View như sau:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"showDetail"]) {

        NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
        NSString *string = [feeds[indexPath.row] objectForKey: @"link"];
        [[segue destinationViewController] setUrl:string];

    }
}

Ở bước cuối cùng ta khởi tạo Web View với url đã chọn để hiển thị nội dung lên Web View:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSURL *myURL = [NSURL URLWithString: [self.url stringByAddingPercentEscapesUsingEncoding:
                                          NSUTF8StringEncoding]];
    NSURLRequest *request = [NSURLRequest requestWithURL:myURL];
    [self.webView loadRequest:request];
}

Vậy là chúng ta đã hoàn thành 1 ứng dụng đơn giản để đọc báo, qua đó hiểu thêm về cách sử dụng TableView và NSXMLParser


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.