(1)XML 数据请求
使用 AFNetworking 中的 AFHTTPRequestOperation 和 AFXMLParserResponseSerializer,另外结合第三方框架 XMLDictionary 进行数据转换
使用 XMLDictionary 的好处:有效避免自行实现 NSXMLParserDelegate 委托代理协议方法来进行繁琐的数据拼凑解析
(2)JSON 数据请求
使用 AFNetworking 中的 AFHTTPRequestOperation 或 AFHTTPRequestOperationManager,另外在图片缓存方面可选的方案有:
使用 AFNetworking 中 的 UIImageView+AFNetworking
使用第三方框架 SDWebImage 的 UIImageView+WebCache
效果如下:
XML 数据格式:
请求网址:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=59287
<ArrayOfString xmlns="http://WebXml.com.cn/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>
广东
</string>
<string>
广州
</string>
<string>
59287
</string>
<string>
59287.jpg
</string>
<string>
2015-9-19 17:30:31
</string>
<string>
25℃/32℃
</string>
<string>
9月19日 多云转中雨
</string>
<string>
无持续风向微风
</string>
<string>
1.gif
</string>
<string>
8.gif
</string>
<string>
今日天气实况:气温:31℃;风向/风力:西南风 1级;湿度:62%;空气质量:暂无;紫外线强度:弱
</string>
<string>
太阳镜指数:必要。建议佩戴透射比为1级的浅色太阳镜。
穿衣指数:炎热。建议穿短衫、短裤等清凉夏季服装。
旅游指数:适宜。微风,虽天气稍热,但不会影响心情。
运动指数:较适宜。户外运动请注意防晒。
洗车指数:不宜。有雨,雨水和泥水会弄脏爱车。
化妆指数:防脱水。请选用防脱水化妆品。
感冒指数:少发。感冒机率较低,避免长期处于空调屋中。
空气污染指数:暂无。
紫外线指数:弱。辐射较弱,涂擦SPF12-15、PA+护肤品。
舒适度指数:较不舒适。多云,有些热。
</string>
<string>
25℃/29℃
</string>
<string>
9月20日 中雨转中到大雨
</string>
<string>
无持续风向微风
</string>
<string>
8.gif
</string>
<string>
22.gif
</string>
<string>
24℃/29℃
</string>
<string>
9月21日 中到大雨转雷阵雨
</string>
<string>
无持续风向微风
</string>
<string>
22.gif
</string>
<string>
4.gif
</string>
<string>
广州是广东省的省会,是中国南方最大的海滨城市,广州位于东经113。17`,北纬23。8`,地处*南部,广东省南部,珠江三角洲北缘。广州临南海,邻近香港特别行政区,是中国通往世界的南大门,广州属丘陵地带。中国的第三大河----珠江从广州市中心穿流而过。广州是一座历史文化名城。相传在远古时候,曾有五位仙人,身穿五色彩服、骑着嘴衔稻穗的五色仙羊降临此地,把稻穗赠给百姓,祝愿这里永无饥荒。从此,广州便有“羊城”、“穗城”的美称,“五羊”也成为广州的象征。广州既是中国也是世界名城,又是一座古城,因历史上有五羊仙子降临献稻穗的故事,广州又称为“羊城”和“穗城”,简称“穗”;广州一年四季如春、繁花似锦,除夕迎春花市闻名海内外,故又有“花城”的美誉。广州地处低纬,属南亚热带季风气候区。地表接受太阳辐射量较多,同时受季风的影响,夏季海洋暖气流形成高温、高湿、多雨的气候;冬季北方大陆冷风形成低温、干燥、少雨的气候。年平均气温为21.4-21.9度,年降雨量平均为1623.6-1899.8mm,北部多于南部。1982年,广州被国务院选定为全国首批历史文化名城之一,是我国重点旅游城市。1999年1月,广州被评为优秀旅游城市。景观:白云山、莲花山、南海神庙、佛山祖庙、广州动物园等。
</string>
</ArrayOfString>
JSON 数据格式:
请求网址:https://alpha-api.app.net/stream/0/posts/stream/global
{
"data": [
{
"canonical_url": "https://alpha.app.net/hasskod2013/post/64791677",
"created_at": "2015-09-19T11:23:30Z",
"entities": {
"hashtags": [
],
"links": [
{
"len": 21,
"pos": 163,
"text": "http://bit.ly/1Ynt5DC",
"url": "http://bit.ly/1Ynt5DC"
}
],
"mentions": [
]
},
"html": "<span itemscope=\"https://app.net/schemas/Post\">Oman says ambassador's home hit in Yemen: Foreign ministry condemns incident in Sanaa as Arab coalition bombards Houthi-held sites as part of move to retake city. <a href=\"http://bit.ly/1Ynt5DC\">http://bit.ly/1Ynt5DC</a></span>",
"id": "64791677",
"machine_only": false,
"num_replies": 0,
"num_reposts": 0,
"num_stars": 0,
"pagination_id": "64791677",
"source": {
"client_id": "8dWzbxxwZeTTAH3v7Yy9TbJ82W6mexqH",
"link": "http://twitterfeed.com",
"name": "twitterfeed"
},
"text": "Oman says ambassador's home hit in Yemen: Foreign ministry condemns incident in Sanaa as Arab coalition bombards Houthi-held sites as part of move to retake city. http://bit.ly/1Ynt5DC",
"thread_id": "64791677",
"user": {
"avatar_image": {
"height": 80,
"is_default": false,
"url": "https://d2rfichhc2fb9n.cloudfront.net/image/5/8crtOD1QaZ4b0uA6GnTQQMVTgJJ7InMiOiJzMyIsImIiOiJhZG4tdXNlci1hc3NldHMiLCJrIjoiYXNzZXRzL3VzZXIvMjMvZmIvNTAvMjNmYjUwMDAwMDAwMDAwMC5wbmciLCJvIjoiIn0",
"width": 80
},
"canonical_url": "https://alpha.app.net/hasskod2013",
"counts": {
"followers": 16,
"following": 33,
"posts": 11722,
"stars": 0
},
"cover_image": {
"height": 260,
"is_default": true,
"url": "https://d2rfichhc2fb9n.cloudfront.net/image/5/kZ-JRmTbmd3WVPswTJ8Nwxzkf917InMiOiJzMyIsImIiOiJ0YXBwLWFzc2V0cyIsImsiOiJpL1UvaS9ZL1VpWW5xRFNvTUtyTEhLNXA0OHN2NkxmTmRVMC5qcGciLCJvIjoiIn0",
"width": 960
},
"created_at": "2013-08-28T11:18:40Z",
"id": "155975",
"locale": "ar_AA",
"name": "hasskod",
"timezone": "Asia/Baghdad",
"type": "feed",
"username": "hasskod2013"
}
},
//同样格式的19个数组元素内容,这里省略...
],
"meta": {
"code": 200,
"max_id": "64791677",
"min_id": "64791658",
"more": true
}
}
ViewController.h
#import <UIKit/UIKit.h> @interface ViewController : UITableViewController
@property (copy, nonatomic) NSArray *arrSampleName; - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName; @end
ViewController.m
#import "ViewController.h"
#import "XMLRequestViewController.h"
#import "JSONRequestViewController.h" @interface ViewController ()
- (void)layoutUI;
@end @implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName {
if (self = [super initWithStyle:UITableViewStyleGrouped]) {
self.navigationItem.title = @"使用 AFNetworking 进行数据请求";
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil]; _arrSampleName = arrSampleName;
}
return self;
} - (void)layoutUI { } #pragma mark - UITableViewController相关方法重写
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 0.1;
} - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_arrSampleName count];
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = _arrSampleName[indexPath.row];
return cell;
} - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.row) {
case : {
XMLRequestViewController *XMLRequestVC = [XMLRequestViewController new];
[self.navigationController pushViewController:XMLRequestVC animated:YES];
break;
}
case : {
JSONRequestViewController *JSONRequestVC = [JSONRequestViewController new];
[self.navigationController pushViewController:JSONRequestVC animated:YES];
break; /*
类似堆栈的先进后出的原理:
返回到(上一级)、(任意级)、(根级)导航
[self.navigationController popViewControllerAnimated:YES];
[self.navigationController popToViewController:thirdSampleVC animated:YES];
[self.navigationController popToRootViewControllerAnimated:YES];
*/
}
default:
break;
}
} @end
PrefixHeader.pch
#define kXMLRequestURLStr @"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName?theCityName=59287"
#define kJSONRequestURLStr @"https://alpha-api.app.net/stream/0/posts/stream/global" #define kTitleOfXMLRequest @"XML 数据请求"
#define kTitleOfJSONRequest @"JSON 数据请求" #define kAvatarImageStr @"avatarImageStr"
#define kName @"name"
#define kText @"text"
#define kLink @"link"
#define kCreatedAt @"createdAt" #define kApplication [UIApplication sharedApplication]
UIButton+BeautifulButton.h
#import <UIKit/UIKit.h> @interface UIButton (BeautifulButton)
/**
* 根据按钮文字颜色,返回对应文字颜色的圆角按钮
*
* @param tintColor 按钮文字颜色;nil 的话就为深灰色
*/
- (void)beautifulButton:(UIColor *)tintColor; @end
UIButton+BeautifulButton.m
#import "UIButton+BeautifulButton.h" @implementation UIButton (BeautifulButton) - (void)beautifulButton:(UIColor *)tintColor {
self.tintColor = tintColor ?: [UIColor darkGrayColor];
self.layer.masksToBounds = YES;
self.layer.cornerRadius = 10.0;
self.layer.borderColor = [UIColor grayColor].CGColor;
self.layer.borderWidth = 1.0;
} @end
NSString+OpenURL.h
#import <UIKit/UIKit.h> @interface NSString (OpenURL)
/**
* 打开浏览器
*/
- (void)openByBrowser; /**
* 打开邮件
*/
- (void)openByEmail; /**
* 拨打电话
*/
- (void)openByTelephone; /**
* 打开短信(Short Messaging Service)
*/
- (void)openBySMS; @end
NSString+OpenURL.m
#import "NSString+OpenURL.h" @implementation NSString (OpenURL) + (void)open:(NSString *)openURLStr {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:openURLStr]];
} - (void)openByBrowser {
[NSString open:self];
} - (void)openByEmail {
[NSString open:[NSString stringWithFormat:@"mailto://%@", self]];
} - (void)openByTelephone {
[NSString open:[NSString stringWithFormat:@"tel://%@", self]];
} - (void)openBySMS {
[NSString open:[NSString stringWithFormat:@"sms://%@", self]];
} @end
KMTableViewCell.h
#import <UIKit/UIKit.h> @interface KMTableViewCell : UITableViewCell
@property (strong, nonatomic) IBOutlet UIImageView *imgVAvatarImage;
@property (strong, nonatomic) IBOutlet UILabel *lblName;
@property (strong, nonatomic) IBOutlet UILabel *lblCreatedAt;
@property (strong, nonatomic) IBOutlet UIImageView *imgVLink; @property (strong, nonatomic) UILabel *lblText;
@property (copy, nonatomic) NSString *avatarImageStr;
@property (copy, nonatomic) NSString *name;
@property (copy, nonatomic) NSString *text;
@property (copy, nonatomic) NSString *createdAt;
@property (assign, nonatomic, getter=isHaveLink) BOOL haveLink; @end
KMTableViewCell.m
#import "KMTableViewCell.h"
//#import "UIImageView+AFNetworking.h"
#import "UIImageView+WebCache.h" static UIImage *placeholderImage;
static CGFloat widthOfLabel;
@implementation KMTableViewCell - (void)awakeFromNib {
// Initialization code
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
placeholderImage = [UIImage imageNamed:@"JSON"];
widthOfLabel = [[UIScreen mainScreen] bounds].size.width - 100.0;
}); _imgVAvatarImage.layer.masksToBounds = YES;
_imgVAvatarImage.layer.cornerRadius = 10.0; //由于 xib 中对标签自适应宽度找不到合适的方式来控制,所以这里用代码编写;这里屏幕复用的 Cell 有几个,就会执行几次 awakeFromNib 方法
_lblText = [[UILabel alloc] initWithFrame:CGRectMake(90.0, 23.0, widthOfLabel, 42.0)];
_lblText.numberOfLines = ;
_lblText.font = [UIFont systemFontOfSize:12.0];
[self addSubview:_lblText];
} - (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated]; // Configure the view for the selected state
} - (void)setAvatarImageStr:(NSString *)avatarImageStr {
if (![_avatarImageStr isEqualToString:avatarImageStr]) {
_avatarImageStr = [avatarImageStr copy];
NSURL *avatarImageURL = [NSURL URLWithString:_avatarImageStr];
//NSData *avatarImageData = [NSData dataWithContentsOfURL:avatarImageURL];
//_imgVAvatarImage.image = [UIImage imageWithData:avatarImageData]; //图片缓存;性能优化的第一步
//方法一:AFNetworking 框架:UIImageView+AFNetworking
// [_imgVAvatarImage setImageWithURL:avatarImageURL
// placeholderImage:placeholderImage]; //方法二:SDWebImage 框架:UIImageView+WebCache
[_imgVAvatarImage sd_setImageWithURL:avatarImageURL
placeholderImage:placeholderImage];
}
} - (void)setName:(NSString *)name {
_name = [name copy];
_lblName.text = _name;
} - (void)setText:(NSString *)text {
_text = [text copy];
_lblText.text = _text;
} - (void)setCreatedAt:(NSString *)createdAt {
_createdAt = [createdAt copy];
_lblCreatedAt.text = _createdAt;
} - (void)setHaveLink:(BOOL)haveLink {
_haveLink = haveLink;
_imgVLink.hidden = !_haveLink;
} @end
KMTableViewCell.xib
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="cellIdentifier" rowHeight="101" id="KGk-i7-Jjw" customClass="KMTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="375" height="101"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3Br-R7-YsD">
<rect key="frame" x="0.0" y="5" width="80" height="80"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="name" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kPR-pa-8uG">
<rect key="frame" x="90" y="2" width="230" height="21"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="created_at" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iAH-dO-aus">
<rect key="frame" x="90" y="64" width="130" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" red="0.40000000596046448" green="0.40000000596046448" blue="0.40000000596046448" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="Action_ReadOriginal" translatesAutoresizingMaskIntoConstraints="NO" id="By5-cw-IJd">
<rect key="frame" x="223" y="60" width="30" height="30"/>
</imageView>
</subviews>
</tableViewCellContentView>
<connections>
<outlet property="imgVAvatarImage" destination="3Br-R7-YsD" id="KaV-vS-y5p"/>
<outlet property="imgVLink" destination="By5-cw-IJd" id="wrr-zz-EqH"/>
<outlet property="lblCreatedAt" destination="iAH-dO-aus" id="BNF-es-fb1"/>
<outlet property="lblName" destination="kPR-pa-8uG" id="BH7-oj-3Kx"/>
</connections>
<point key="canvasLocation" x="254.5" y="377.5"/>
</tableViewCell>
</objects>
<resources>
<image name="Action_ReadOriginal" width="60" height="60"/>
</resources>
</document>
XMLRequestViewController.h
#import <UIKit/UIKit.h> @interface XMLRequestViewController : UIViewController <NSXMLParserDelegate>
@property (strong, nonatomic) UITextView *txtVResult; @property (strong, nonatomic) IBOutlet UIButton *btnSendRequest; @end
XMLRequestViewController.m
#import "XMLRequestViewController.h"
#import "AFNetworking.h"
#import "AFNetworkActivityIndicatorManager.h"
#import "UIButton+BeautifulButton.h"
#import "XMLDictionary.h" @interface XMLRequestViewController ()
- (void)layoutUI;
- (void)convertXMLParserToDictionary:(NSXMLParser *)parser;
@end @implementation XMLRequestViewController - (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (void)layoutUI {
self.navigationItem.title = kTitleOfXMLRequest; [_btnSendRequest beautifulButton:nil]; _txtVResult = [UITextView new];
_txtVResult.editable = NO;
CGRect rect = [[UIScreen mainScreen] bounds];
_txtVResult.frame = CGRectMake(5.0, 64.0, rect.size.width - 10.0, rect.size.height - 164.0);
_txtVResult.font = [UIFont systemFontOfSize:15.0];
_txtVResult.text = @"点击「发送请求」按钮获取天气信息";
[self.view addSubview:_txtVResult]; //启动网络活动指示器;会根据网络交互情况,实时显示或隐藏网络活动指示器;他通过「通知与消息机制」来实现 [UIApplication sharedApplication].networkActivityIndicatorVisible 的控制
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
} - (void)convertXMLParserToDictionary:(NSXMLParser *)parser {
//dictionaryWithXMLParser: 是第三方框架 XMLDictionary 的方法
NSDictionary *dic = [NSDictionary dictionaryWithXMLParser:parser];
NSMutableString *mStrWeatherInfo = [[NSMutableString alloc] initWithString:@"广州近三天天气情况:\n"];
NSArray *arrWeatherInfo = [dic objectForKey:@"string"];
if (arrWeatherInfo != nil && arrWeatherInfo.count > ) {
NSMutableArray *mArrRange = [[NSMutableArray alloc] init]; NSUInteger loc = mStrWeatherInfo.length;
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]];
NSUInteger len = mStrWeatherInfo.length - loc;
NSValue *valObj = [NSValue valueWithRange:NSMakeRange(loc, len)];
[mArrRange addObject:valObj];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]]; loc = mStrWeatherInfo.length;
[mStrWeatherInfo appendFormat:@"\n\n %@", arrWeatherInfo[]];
len = mStrWeatherInfo.length - loc;
valObj = [NSValue valueWithRange:NSMakeRange(loc, len)];
[mArrRange addObject:valObj];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]]; loc = mStrWeatherInfo.length;
[mStrWeatherInfo appendFormat:@"\n\n %@", arrWeatherInfo[]];
len = mStrWeatherInfo.length - loc;
valObj = [NSValue valueWithRange:NSMakeRange(loc, len)];
[mArrRange addObject:valObj];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]];
[mStrWeatherInfo appendFormat:@"\n %@", arrWeatherInfo[]]; [mStrWeatherInfo appendFormat:@"\n\n %@", arrWeatherInfo[]]; //数据的前10个字符以16.0像素加粗显示;这里使用 UITextView 的 attributedText,而他的 text 无法实现这种需求
NSMutableAttributedString *mAttrStr = [[NSMutableAttributedString alloc] initWithString:mStrWeatherInfo];
[mAttrStr addAttribute:NSFontAttributeName
value:[UIFont boldSystemFontOfSize:16.0]
range:NSMakeRange(, )]; //数据的日期部分以紫色显示
for (NSValue *valObj in mArrRange) {
NSRange currentRange;
[valObj getValue:¤tRange];
[mAttrStr addAttribute:NSForegroundColorAttributeName
value:[UIColor purpleColor]
range:currentRange];
} //数据的前10个字符之后的内容全部以15.0像素显示
[mAttrStr addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:15.0]
range:NSMakeRange(, mStrWeatherInfo.length - )]; _txtVResult.attributedText = mAttrStr;
} else {
_txtVResult.text = @"请求数据无效";
} } - (IBAction)sendRequest:(id)sender {
NSURL *requestURL = [NSURL URLWithString:kXMLRequestURLStr];
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
op.responseSerializer = [AFXMLParserResponseSerializer serializer];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
NSXMLParser *parser = (NSXMLParser *)responseObject;
//这里使用了第三方框架 XMLDictionary,他本身继承并实现 NSXMLParserDelegate 委托代理协议,对数据进行遍历处理
[self convertXMLParserToDictionary:parser]; //parser.delegate = self;
//parser.shouldProcessNamespaces = YES;
//[parser parse];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
//start 是 AFNetworking 的自定义方法,他在自定义的线程中去执行操作;不是 NSOperation 对象实例的 start 方法,所以可以不用使用把操作添加到操作主队列的方法:[[NSOperationQueue mainQueue] addOperation:op]
[op start];
} #pragma mark -
#pragma mark NSXMLParserDelegate
/* 开始解析 XML 文件,在开始解析 XML 节点前,通过该方法可以做一些初始化工作 */
- (void)parserDidStartDocument:(NSXMLParser *)parser {
NSLog(@"开始解析 XML 文件");
} /* 当解析器对象遇到 XML 的开始标记时,调用这个方法开始解析该节点 */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict {
NSLog(@"发现节点:%@", elementName);
} /* 当解析器找到开始标记和结束标记之间的字符时,调用这个方法解析当前节点的所有字符 */
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSLog(@"正在解析节点内容:%@", string);
} /* 当解析器对象遇到 XML 的结束标记时,调用这个方法完成解析该节点 */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog(@"解析节点结束:%@", elementName);
} /* 解析 XML 出错的处理方法 */
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSLog(@"解析 XML 出错:%@", parseError);
} /* 解析 XML 文件结束 */
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(@"解析 XML 文件结束");
} @end
XMLRequestViewController.xib
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="XMLRequestViewController">
<connections>
<outlet property="btnSendRequest" destination="zCQ-LM-grx" id="tgt-2z-WaB"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zCQ-LM-grx">
<rect key="frame" x="250" y="520" width="100" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="V3R-30-5vV"/>
<constraint firstAttribute="height" constant="40" id="yct-84-Mk4"/>
</constraints>
<state key="normal" title="发送请求">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="sendRequest:" destination="-1" eventType="touchUpInside" id="8zG-Dl-erk"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="zCQ-LM-grx" secondAttribute="bottom" constant="40" id="DBx-zw-hdG"/>
<constraint firstAttribute="centerX" secondItem="zCQ-LM-grx" secondAttribute="centerX" id="F2b-L7-BR9"/>
</constraints>
</view>
</objects>
</document>
JSONRequestViewController.h
#import <UIKit/UIKit.h> @interface JSONRequestViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UIWebViewDelegate>
@property (strong, nonatomic) NSMutableArray *mArrCell;
@property (strong, nonatomic) UITableView *tableView;
@property (strong, nonatomic) UILabel *lblEmptyDataMsg;
@property (strong, nonatomic) UIWebView *webView; @property (strong, nonatomic) IBOutlet UIButton *btnSendRequest; @end
JSONRequestViewController.m
#import "JSONRequestViewController.h"
#import "AFNetworking.h"
#import "AFNetworkActivityIndicatorManager.h"
#import "UIButton+BeautifulButton.h"
#import "KMTableViewCell.h"
#import "NSString+OpenURL.h" static NSString *cellIdentifier = @"cellIdentifier";
@interface JSONRequestViewController ()
- (void)layoutUI;
- (NSString *)displayTimeFromCreatedAt:(NSString *)createdAt;
- (void)loadData:(NSArray *)arrData;
@end @implementation JSONRequestViewController - (void)viewDidLoad {
[super viewDidLoad]; [self layoutUI];
} - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} - (void)layoutUI {
self.navigationItem.title = kTitleOfJSONRequest; [_btnSendRequest beautifulButton:nil]; _mArrCell = [[NSMutableArray alloc] initWithCapacity:]; CGRect rect = [[UIScreen mainScreen] bounds];
CGRect frame = CGRectMake(5.0, 64.0, rect.size.width - 10.0, rect.size.height - 164.0);
_tableView =[[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain];
_tableView.dataSource = self;
_tableView.delegate = self;
//设置边距,解决单元格分割线默认偏移像素过多的问题
if ([_tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[_tableView setSeparatorInset:UIEdgeInsetsZero]; //设置单元格(上左下右)内边距
}
if ([_tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[_tableView setLayoutMargins:UIEdgeInsetsZero]; //设置单元格(上左下右)外边距
}
[self.view addSubview:_tableView]; //注册可复用的单元格
UINib *nib = [UINib nibWithNibName:@"KMTableViewCell" bundle:nil];
[_tableView registerNib:nib forCellReuseIdentifier:cellIdentifier]; //空数据时,显示的提示内容
_lblEmptyDataMsg = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 300.0, 50.0)];
CGPoint newPoint = _tableView.center;
newPoint.y -= 45.0;
_lblEmptyDataMsg.center = newPoint;
_lblEmptyDataMsg.text = @"点击「发送请求」按钮获取全球新闻信息";
_lblEmptyDataMsg.textColor = [UIColor grayColor];
_lblEmptyDataMsg.textAlignment = NSTextAlignmentCenter;
_lblEmptyDataMsg.font = [UIFont systemFontOfSize:16.0];
[_tableView addSubview:_lblEmptyDataMsg]; //点击单元格时,显示的新闻信息详细内容
frame = CGRectMake(10.0, CGRectGetMidY(rect) - 200.0, rect.size.width - 20.0, 400.0);
_webView = [[UIWebView alloc] initWithFrame:frame];
_webView.layer.borderColor = [UIColor lightGrayColor].CGColor;
_webView.layer.borderWidth = 1.0;
_webView.delegate = self;
_webView.hidden = YES;
[self.view addSubview:_webView]; [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
} - (NSString *)displayTimeFromCreatedAt:(NSString *)createdAt {
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; //「2015-09-15T13:23:28Z」
NSDate *date = [dateFormat dateFromString:createdAt]; NSTimeZone *zone = [NSTimeZone systemTimeZone];
NSInteger interval = [zone secondsFromGMTForDate:date]; //跟 GMT 时间相差8小时
date = [date dateByAddingTimeInterval:interval];
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; //转化为「2015-09-15 21:23:28」
NSString *displayTime = [dateFormat stringFromDate:date];
return displayTime;
} - (void)loadData:(NSArray *)arrData {
_mArrCell = [NSMutableArray new];
[arrData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSMutableDictionary *mDicCell = [NSMutableDictionary new];
NSDictionary *dicRoot = (NSDictionary *)obj;
NSArray *arrLink = [dicRoot valueForKeyPath:@"entities.links"];
[mDicCell setValue:[NSString stringWithFormat:@"%@?w=80&h=80",
[dicRoot valueForKeyPath:@"user.avatar_image.url"]]
forKey:kAvatarImageStr];
[mDicCell setValue:[dicRoot valueForKeyPath:@"user.name"] forKey:kName];
[mDicCell setValue:[dicRoot valueForKey:@"text"] forKey:kText];
[mDicCell setValue:(arrLink.count > ? [arrLink[] valueForKey:@"url"] : @"")
forKey:kLink];
[mDicCell setValue:[self displayTimeFromCreatedAt:[dicRoot valueForKey:@"created_at"]]
forKey:kCreatedAt];
[_mArrCell addObject:mDicCell];
}];
[self.tableView reloadData];
} - (IBAction)sendRequest:(id)sender {
_lblEmptyDataMsg.text = @"加载中...";
_webView.hidden = YES; //方法一:AFHTTPRequestOperation
// NSURL *requestURL = [NSURL URLWithString:kJSONRequestURLStr];
// NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
// AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
// op.responseSerializer = [AFJSONResponseSerializer serializer];
// [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// NSDictionary *dic = (NSDictionary *)responseObject;
// [self loadData:(NSArray *)dic[@"data"]];
// } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// NSLog(@"Error: %@", error);
// }];
// //start 是 AFNetworking 的自定义方法,他在自定义的线程中去执行操作;不是 NSOperation 对象实例的 start 方法,所以可以不用使用把操作添加到操作主队列的方法:[[NSOperationQueue mainQueue] addOperation:op]
// [op start]; //方法二:AFHTTPRequestOperationManager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:kJSONRequestURLStr parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *dic = (NSDictionary *)responseObject;
[self loadData:(NSArray *)dic[@"data"]];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
} - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
_webView.hidden = YES;
} #pragma mark - TableView
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return @"全球新闻信息列表";
} - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return ;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSUInteger count = _mArrCell.count;
_lblEmptyDataMsg.hidden = count > ; return count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
KMTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[KMTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:cellIdentifier];
} NSMutableDictionary *mDicCell = _mArrCell[indexPath.row];
cell.avatarImageStr = mDicCell[kAvatarImageStr];
cell.name = mDicCell[kName];
cell.text = mDicCell[kText];
cell.createdAt = mDicCell[kCreatedAt];
cell.haveLink = [mDicCell[kLink] length] > ; //可以通过 isHaveLink 或 haveLink 获取值
return cell;
} - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 90.0;
} - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
/*
viewDidLoad 中对应的操作
if ([_tableView respondsToSelector:@selector(setSeparatorInset:)]) {
[_tableView setSeparatorInset:UIEdgeInsetsZero]; //设置单元格(上左下右)内边距
}
if ([_tableView respondsToSelector:@selector(setLayoutMargins:)]) {
[_tableView setLayoutMargins:UIEdgeInsetsZero]; //设置单元格(上左下右)外边距
}
*/ if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
} - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableDictionary *mDicCell = _mArrCell[indexPath.row];
NSString *link = mDicCell[kLink];
if (link.length > ) {
//使用浏览器打开网址
//[link openByBrowser]; //使用 WebView 打开网址;由于这里很多网址是外国的,存在有的访问不了、有的访问慢导致加载超时的情况
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:link]];
[_webView loadRequest:request];
_webView.hidden = NO;
}
} #pragma mark - WebView
- (void)webViewDidStartLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = YES;
} - (void)webViewDidFinishLoad:(UIWebView *)webView {
kApplication.networkActivityIndicatorVisible = NO;
} - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
NSLog(@"Error: %@", error);
webView.hidden = YES;
kApplication.networkActivityIndicatorVisible = NO;
UIAlertView *alertVCustom = [[UIAlertView alloc] initWithTitle:@"提示信息"
message:@"网络连接错误"
delegate:nil
cancelButtonTitle:@"确定"
otherButtonTitles:nil, nil];
[alertVCustom show];
} @end
JSONRequestViewController.xib
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="JSONRequestViewController">
<connections>
<outlet property="btnSendRequest" destination="zCQ-LM-grx" id="tgt-2z-WaB"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="zCQ-LM-grx">
<rect key="frame" x="250" y="520" width="100" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="100" id="V3R-30-5vV"/>
<constraint firstAttribute="height" constant="40" id="yct-84-Mk4"/>
</constraints>
<state key="normal" title="发送请求">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="sendRequest:" destination="-1" eventType="touchUpInside" id="8zG-Dl-erk"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="zCQ-LM-grx" secondAttribute="bottom" constant="40" id="DBx-zw-hdG"/>
<constraint firstAttribute="centerX" secondItem="zCQ-LM-grx" secondAttribute="centerX" id="F2b-L7-BR9"/>
</constraints>
</view>
</objects>
</document>
AppDelegate.h
#import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UINavigationController *navigationController; @end
AppDelegate.m
#import "AppDelegate.h"
#import "ViewController.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController *viewController = [[ViewController alloc]
initWithSampleNameArray:@[ kTitleOfXMLRequest,
kTitleOfJSONRequest ]];
_navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
_window.rootViewController = _navigationController;
//[_window addSubview:_navigationController.view]; //当_window.rootViewController关联时,这一句可有可无
[_window makeKeyAndVisible];
return YES;
} - (void)applicationWillResignActive:(UIApplication *)application {
} - (void)applicationDidEnterBackground:(UIApplication *)application {
} - (void)applicationWillEnterForeground:(UIApplication *)application {
} - (void)applicationDidBecomeActive:(UIApplication *)application {
} - (void)applicationWillTerminate:(UIApplication *)application {
} @end