完成予想図
THE雑ですがGitHubに今回作成したソースをプッシュしておきました
作業環境
- OSX 10.11.6
- Xcode7.3.1
- Objective-C
- CocoaPods 0.39.0
- AFNetworking 3.1.0
準備
ここまで準備をしてから始めます。
面倒なのでMVCで実装します。
使用するデータ
サンプル XML ファイル (books.xml) | MicroSoft
上記データを使わせていただきます!!
また、データは私のサーバにアップロードしているので使いたい方は使ってください!
catalog
→book
→→author
→→title
→→genre
→→price
→→publish_date
→→description
上記のようなデータ構造になっているのでTableViewにデータを表示させてみようと思います!
(矢印が入れ子)
実装
XML整形ライブラリ
使用するライブラリ?
https://github.com/nnsnodnb/XML-to-NSDictionary
→ 本家
自分なりにARCに対応させました。開発がすでに止まっているのでPRを出してもマージされることはないでしょう!
vender
フォルダに XmlReader.h
及び XmlReader.m
を突っ込んでおく!
Model Object
Bookクラスを作っておく。中身は以下
#import <Foundation/Foundation.h>
@interface Book : NSObject
@property (nonatomic) NSString *author;
@property (nonatomic) NSString *title;
@property (nonatomic) NSString *genre;
@property (nonatomic) NSString *price;
@property (nonatomic) NSString *publishDate;
@property (nonatomic) NSString *bookDescription;
@end
description
に関しては予約語なので bookDescription
とした
TableViewCell クラス
#import <UIKit/UIKit.h>
#import "Book.h"
@interface TableViewCell : UITableViewCell
@property (weak, nonatomic) IBOutlet UILabel *authorLabel;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *genreLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *publicDateLabel;
@property (weak, nonatomic) IBOutlet UILabel *descriptionLabel;
- (void)setConfigure:(Book *)model;
@end
#import "TableViewCell.h"
@implementation TableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
- (void)setConfigure:(Book *)model {
self.authorLabel.text = [model.author stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.titleLabel.text = [model.title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.genreLabel.text = [model.genre stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.priceLabel.text = [model.price stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.publicDateLabel.text = [model.publishDate stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
self.descriptionLabel.text = [model.bookDescription stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
@end
改行が含まれていたので改行を削除する処理をしています。
当たり前なところは端折りながらやります!
デザイン性に欠けていますがとりあえずこんな感じでstoryboardを編集
DescriptionはLineを0に設定しています。
XML整形ライブラリの補足
なんかkeyの中に更にkeyが入っているという謎仕様ww
AFNetworking当たりのお仕事
#import <Foundation/Foundation.h>
#import "Book.h"
@protocol CallBackDelegate <NSObject>
- (void)callbackWithError;
@end
typedef void (^Callback)(NSArray<Book *>* dataSource);
@interface GetXmlData : NSObject
@property (weak, nonatomic) id<CallBackDelegate> delegate;
- (void)requestXmlDataWithCallback:(Callback)callback;
@end
#import "GetXmlData.h"
#import "XMLReader.h"
#import <AFNetworking/AFNetworking.h>
static NSString *const accessUrl = @"https://dl.nnsnodnb.moe/ios-app/sample.xml";
@implementation GetXmlData
- (void)requestXmlDataWithCallback:(Callback)callback {
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
AFHTTPResponseSerializer * responseSerializer = [AFHTTPResponseSerializer serializer];
responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/xml", nil];
manager.responseSerializer = responseSerializer;
manager.requestSerializer = requestSerializer;
NSMutableArray<Book *> *dataSource = [NSMutableArray array];
__weak typeof (self) wself = self;
[manager GET:accessUrl
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSData *data = (NSData *)responseObject;
NSDictionary<NSString *, NSDictionary *> *dictionary = [XMLReader dictionaryForXMLData:data
error:nil];
NSDictionary<NSString *, NSDictionary *> *category = dictionary[@"catalog"];
for (NSDictionary<NSString *, NSDictionary *> *book in category[@"book"]) {
Book *model = [Book new];
model.author = book[@"author"][@"text"];
model.title = book[@"title"][@"text"];
model.genre = book[@"genre"][@"text"];
model.price = book[@"price"][@"text"];
model.publishDate = book[@"publish_date"][@"text"];
model.bookDescription = book[@"description"][@"text"];
[dataSource addObject:model];
}
callback(dataSource);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if ([wself.delegate respondsToSelector:@selector(callbackWithError)]) {
[wself.delegate callbackWithError];
}
}];
}
@end
+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError *)error;
上記のようなクラスメソッドが用意されているので responseObject
をNSDataに変換してあげて、このメソッドに当ててあげるとグチャグチャなNSDictionaryが返ってきます!!
こんなものか。
ViewControllerは?
#import "Book.h"
#import "GetXmlData.h"
#import "TableViewCell.h"
#import "ViewController.h"
@interface ViewController () <UITableViewDataSource, UITableViewDelegate, CallBackDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic) NSArray<Book *> *dataSource;
@property (nonatomic) GetXmlData *getXmlData;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = [NSArray array];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.getXmlData = [GetXmlData new];
self.getXmlData.delegate = self;
__weak typeof (self) wself = self;
[self.getXmlData requestXmlDataWithCallback:^(NSArray<Book *> *dataSource) {
wself.dataSource = dataSource;
[wself.tableView reloadData];
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"
forIndexPath:indexPath];
[cell setConfigure:self.dataSource[indexPath.row]];
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#pragma mark - CallBackDelegate
- (void)callbackWithError {
NSLog(@"Error");
}
@end
最後に
なんか最後はぶっ飛ばしで行きましたが、なんとかなったのではないでしょうか?
今回使用したデータが悪かったのかなんかちょっと時間をかけすぎてしまいました。