/*
通过block回调
定义block代码块,目的是解析完成之后调用
返回值是 void
參数是 数组,里面的每一个成员是一个NSString*/
typedef void(^WeatherFinishedBlock)(NSArray *dataList);
@interface WeatherXMLPaser : NSObject
// 解析器解析数据,參数1是要解析的数据,參数2是解析完成回调的代码块
- (void)parserWeatherData:(NSData *)data
completion:(WeatherFinishedBlock)completion;
@end
//--------------------------------------------------------
@interface WeatherXMLPaser() <NSXMLParserDelegate>
{
// 成员记住block代码块
WeatherFinishedBlock _FinishedBlock;
}
@end
//---------------------------------------------------------
#pragma mark - 成员方法
#pragma mark 解析器解析数据,參数1是要解析的数据,參数2是完成时调用的代码块
- (void)parserWeatherData:(NSData *)data
completion:(WeatherFinishedBlock)completion
{
// 0. 记录块代码
_FinishedBlock = completion;
// 1. 实例化XML解析器
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
// 2. 设置代理为 当前的WeatherXMLPaser
[parser setDelegate:self];
// 3. 解析器開始解析
[parser parse];
}
//--------------------------------------------------------
#pragma mark - XML解析代理方法,结束解析文档
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// 解析结束,调用代码块,參数是,解析完的成员NSString数组
// 通过block代码块回调,通知调用方解析结果
_FinishedBlock(_dataList);
}
//--------------------------------------------------------
// 1) 实例化单例 天气XML解析器
WeatherXMLPaser *parser = [WeatherXMLPaser sharedWeatherXMLPaser];
// 2)解析器解析数据,參数1是要解析的数据,參数2是解析完成要运行的代码块
// 而且将解析完的数组 作为參数传递进来
[parser parserWeatherData:data completion:^(NSArray *dataList) {
// 解析完成了,打印输出
Weather *w = [Weather weatherWithArray:dataList];
}];
H:/1021/00_Singleton单例.m
/*
单例3步曲
1,静态实例变量
2,类方法,allocWithZone
3,类方法,sharedXXX
*/
// 单例第1步:静态实例变量
static WeatherXMLPaser *sharedInstance;
// 单例第2步:类方法,allocWithZone
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
// 单例第3步:类方法,shared方法
+ (WeatherXMLPaser *)sharedWeatherXMLPaser
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// alloc方法会自己主动调用allocWithZone方法
sharedInstance = [[WeatherXMLPaser alloc]init];
});
return sharedInstance;
}
H:/1021/01_地图_MainViewController.m
// MainViewController.m
// 01.地图
// Created by apple on 13-10-21.
// Copyright (c) 2013年 itcast. All rights reserved.
/*
#import <UIKit/UIKit.h>
@interface MainViewController : UIViewController
@end
*/
#import "MainViewController.h"
#import <MapKit/MapKit.h>
//#import "MyAnnotation.h"
#import "MyAnnotation2.h"
@interface MainViewController () <MKMapViewDelegate>
{
MKMapView *_mapView;
}
@end
@implementation MainViewController
/**
1. 地图跟踪模式
MKUserTrackingMode None = 0 不跟踪用户位置
MKUserTrackingMode Follow 跟踪用户位置
MKUserTrackingMode FollowWithHeading 带方向跟踪用户位置(汽车车头方向)
2. 地图模式
MKMapType Standard = 0, 标准地图(最省电的模式)
MKMapType Satellite, 卫星地图
MKMapType Hybrid 混合地图(最费电)
3. 设置地图显示区域。距离以米为单位(iOS7升级的,不再自己主动调整地图现实比例)
MKCoordinateRegion MKCoordinateRegionMakeWithDistance
4. 加入大头针
addAnnotation:(id <MKAnnotation>)annotation
凡是遵守MKAnnotation协议的对象都能够成为大头针
5. 自己定义大头针,地图视图是支持大头针视图重用的!
假设在mapView:(MKMapView *)mapView viewForAnnotation:
(id<MKAnnotation>)annotation
方法中,返回nil。地图视图会使用默认的方法绘制大头针
假设重写了mapView:viewForAnnotation方法,在程序中。调用
addAnnotation:annotation方法时,
annotation会以參数的形式传递给自己定义大头针视图的方法
提示:假设是自己定义大头针视图。须要设置canShowCallout属性,
才干够和视图进行交互
6. 假设重写了mapView:viewForAnnotation方法
跟踪用户信息时,相同会调用该方法!
假设既要跟踪用户信息,同一时候又要显示大头针
(譬如:显示汽车位置。同一时候显示加油站的大头针)
假设传入的annotation不是自己定义大头针视图,直接返回nil,
使用地图默认的方法绘制大头针
假设是自己定义视图,则设置大头针属性
*/
#pragma mark - 实例化视图
- (void)loadView
{
// 设置全屏
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
// 1. 实例化地图视图
MKMapView *mapView = [[MKMapView alloc]initWithFrame:self.view.bounds];
[self.view addSubview:mapView];
// 设置MapView的代理为当前控制器
[mapView setDelegate:self];
// 2. 设置跟踪用户位置的模式
[mapView setUserTrackingMode:MKUserTrackingModeFollow animated:YES];
// 3. 设置地图的类型
[mapView setMapType:MKMapTypeHybrid];
_mapView = mapView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// 依据经纬度,生成Coordinate2D坐标
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(+30.06055580, +116.34273116);
// 默认大头针,通过Coordinate2D生成大头针 annotation
MyAnnotation *annotation = [[MyAnnotation alloc]initWithCoordinate:coord title:@"我的地盘" subtitle:nil];
// 自己定义大头针,能够通过setter方法生成大头针 annotation2
MyAnnotation2 *annotation = [[MyAnnotation2 alloc]init];
[annotation setCoordinate:coord];
[annotation setTitle:@"我的地盘"];
[annotation setIcon:@"head0.png"];
NSLog(@"%p %@", annotation, annotation);
// 加入大头针到mapView
[_mapView addAnnotation:annotation];
// 自己定义大头针,能够通过setter方法生成大头针 annotation2
MyAnnotation2 *annotation2 = [[MyAnnotation2 alloc]init];
// 依据经纬度,生成Coordinate2D坐标
CLLocationCoordinate2D coord2 = CLLocationCoordinate2DMake(+50.06055580, +116.34273116);
[annotation2 setCoordinate:coord2];
[annotation2 setTitle:@"MJ"];
[annotation2 setIcon:@"head0.png"];
// 加入大头针到mapView
[_mapView addAnnotation:annotation2];
// 依据Coordinate2D坐标的经纬度,生成Location对象
CLLocation *location1 = [[CLLocation alloc]initWithLatitude:coord.latitude longitude:coord.longitude];
// 依据Coordinate2D坐标的经纬度,生成Location对象
CLLocation *location2 = [[CLLocation alloc]initWithLatitude:coord2.latitude longitude:coord2.longitude];
// 计算两个Location对象之间的距离
CLLocationDistance distance = [location1 distanceFromLocation:location2];
NSLog(@"两点间距离 %f", distance);
}
#pragma mark - 地图代理方法
#pragma mark 每次用户位置变化都会被调用,意味着很费电
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(@"%@ %@", userLocation.location, userLocation.title);
// 利用location中的经纬度设置地图显示的坐标区域CoordinateRegion
// 參数2,和參数3的意思是:X,Y半径
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(
userLocation.location.coordinate, 100.0, 100.0);
// 设置地图的显示区域。以用户所在位置为中心点,半径为100米
[mapView setRegion:region animated:YES];
}
#pragma mark - 自己定义大头针视图,參数中的annotation就是加入到mapView的大头针
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id<MKAnnotation>)annotation
{
// 假设传入的annotation不是自己定义大头针视图。直接返回nil,
// 即使用地图默认的方法绘制大头针
// 假设是自己定义视图。才要设置大头针属性,牢记~~~~
if (![annotation isKindOfClass:[MyAnnotation2 class]]) {
return nil;
}
// 同cell,标准优化代码
static NSString *ID = @"ID";
MKAnnotationView *view = [mapView
dequeueReusableAnnotationViewWithIdentifier:ID];
// 假设没有找到可重用的大头针视图,才实例化新的
if (view == nil) {
view = [[MKAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:ID];
// 点击大头针,能够突显出来
view.canShowCallout = YES;
}
// 设置大头针视图独一无二的属性
// 1) 假设大头针视图是从缓冲池取出的,必须要又一次设置大头针
[view setAnnotation:annotation];
// 2) 设置大头针图像,需手动转成MyAnnotation2 *,才干使用子类的特有属性
[view setImage:[UIImage imageNamed:((MyAnnotation2 *)annotation).icon]];
return view;
}
@end
H:/1021/01_地图_MyAnnotation.m
// MyAnnotation.m
// 01.地图
// Created by apple on 13-10-21.
// Copyright (c) 2013年 itcast. All rights reserved.
/*
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
// 大头针,遵守协议 <MKAnnotation>
@interface MyAnnotation : NSObject <MKAnnotation>
// 提示。由于要给对象属性赋值,所以此处实例化对象方法不能用工厂方法,
原因就是类方法中,无法訪问对象的成员变量
// 坐标,标题,子标题
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)title subtitle:(NSString *)subtitle;
@end
*/
#import "MyAnnotation.h"
@interface MyAnnotation()
{
CLLocationCoordinate2D _coordinate;
NSString *_title;
NSString *_subtitle;
}
@property (strong, nonatomic) NSString *strong_str1;
@property (copy, nonatomic) NSString *copy_str2;
@end
@implementation MyAnnotation
/*
copy copy经常使用于NSString,目的是改变新的不影响旧的
copy出来的对象是不可变对象,
而mutableCopy出来的是可变对象
因此,仅仅有对不可变对象进行copy的时候,相当于retain
属性是非arc的,可是在arc中相同能够使用。表示对象是能够复制的
使用copy描写叙述符,在给对象赋值时。会建立对象的副本
在非arc开发中,字符串类型NSString通常使用copy描写叙述符
copy属性通常被称为深复制
strong 属于arc的,在非arc中不能够使用。等同于非arc中的retain
使用strong描写叙述符,在给对象赋值时,会建立对象的指针副本
strong属性通常被称为浅复制
在性能上strong会稍微比copy要好,建议大家在日常开发中使用strong。
*/
- (id)initWithCoordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)title subtitle:(NSString *)subtitle
{
if (self = [super init]) {
// 为成员赋值
_coordinate = coordinate;
_title = title;
_subtitle = subtitle;
NSMutableString *string = [NSMutableString string];
[string setString:@"oldValue"];
// strong 浅拷贝,仅仅是建立指针副本
self.strong_str1 = string;
// copy 深拷贝,建立对象副本
self.copy_str2 = string;
// 因此,string和strong_str1两个指针指向的是同一个地址
// 而copy_str2指向的是一个新的地址(新复制的对象的地址)
NSLog(@"%p %p %p", string, self.strong_str1, self.copy_str2);
[string setString:@"newValue"];
// string和strong_str1指向同一个,故结果是newValue
// copy_str2指向的是一个新开的地址,故结果依旧是oldValue
NSLog(@"%@ %@ %@", string, self.strong_str1, self.copy_str2);
}
return self;
}
#pragma mark - 仅仅读属性,即仅仅有getter方法
- (CLLocationCoordinate2D)coordinate
{
return _coordinate;
}
- (NSString *)title
{
return _title;
}
- (NSString *)subtitle
{
return _subtitle;
}
@end
H:/1021/01_地图_MyAnnotation2.h
//
// MyAnnotation2.h
// 01.地图
//
// Created by apple on 13-10-21.
// Copyright (c) 2013年 itcast. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
// 自己定义大头针,遵守协议 <MKAnnotation>
@interface MyAnnotation2 : NSObject <MKAnnotation>
// 坐标,标题,副标题
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
// 大头针图标的名字
@property (nonatomic, strong) NSString *icon;
@end
H:/1021/02_定位_MainViewController.m
// MainViewController.m
// 02.定位
// Created by apple on 13-10-21.
// Copyright (c) 2013年 itcast. All rights reserved.
#import "MainViewController.h"
#import <CoreLocation/CoreLocation.h>
@interface MainViewController () <CLLocationManagerDelegate>
{
// 成员:LocationManager定位管理器
CLLocationManager *_locationManager;
// 成员:Geocoder 地理位置编码器
CLGeocoder *_geocoder;
}
@end
@implementation MainViewController
/*
1. 要使用定位服务。都是从CLLocationManager開始的
2. 在实际应用开发中。须要推断用户的定位服务是否打开,
假设没有打开。须要提示用户
直接用定位管理器的类方法locationServicesEnabled能够推断。
3. 在大多数情况下CLLocation的精度不如MKMapView高。可是由于不使用UIMapView。
相对性能较好!
4. 使用CLLocation时。最好设置定位精度。以省电
kCLLocationAccuracy Best; // 最佳精度(最耗电)
kCLLocationAccuracy NearestTenMeters; // 近期10米范围内定位
kCLLocationAccuracy HundredMeters; // 百米
kCLLocationAccuracy Kilometer; // 千米
kCLLocationAccuracy ThreeKilometers; // 3000米
使用startUpdatingLocation能够開始定位用户位置
假设不须要持续跟踪用户的行踪,定位之后,
最好stopUpdatingLocation替用户省电!
5. 依据经纬度计算地名
- (void)reverseGeocodeLocation:(CLLocation *)location
completionHandler:(CLGeocodeCompletionHandler)completionHandler;
6. 依据地名计算经纬度
- (void)geocodeAddressString:(NSString *)addressString
completionHandler:(CLGeocodeCompletionHandler)completionHandler;
*/
- (void)viewDidLoad
{
[super viewDidLoad];
// 1. 推断定位服务是否可用
if ([CLLocationManager locationServicesEnabled]) {
// 1) 实例化定位管理器
_locationManager = [[CLLocationManager alloc]init];
// 2) 设置定位管理器的代理,当位置变化时,会调用代理的方法
[_locationManager setDelegate:self];
// 3) 设置定位管理器的精度
[_locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
// 4) 开启用户定位功能
[_locationManager startUpdatingLocation];
// 5) 实例化geocoder
_geocoder = [[CLGeocoder alloc]init];
// 依据地名,反向解析出坐标
[_geocoder geocodeAddressString:@"西湖"
completionHandler:^(NSArray *placemarks, NSError *error) {
// placemarks 地点、地标
CLPlacemark *placemark = placemarks[0];
NSLog(@"%@ %@", placemark.location, placemark.country);
}];
} else {
NSLog(@"没有开启定位服务");
}
}
#pragma mark - 定位管理器代理方法
#pragma mark 更新位置。仅仅要用户的位置发生变化,就会被调用,很费电!
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
// 数组locations中仅仅有一个位置
NSLog(@"%@", locations[0]);
// 依据地名,反向解析出坐标
[_geocoder reverseGeocodeLocation:locations[0]
completionHandler:^(NSArray *placemarks, NSError *error) {
// placemarks 地点、地标
CLPlacemark *placemark = placemarks[0];
// 中国北京市昌平区回龙观地区建材城西路67号
NSLog(@"%@", placemark);
}];
}
@end
H:/1021/03_天气预报_MainViewController.m
// MainViewController.m
// 03.天气预报
// Created by apple on 13-10-21.
// Copyright (c) 2013年 itcast. All rights reserved.
#import "MainViewController.h"
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "WeatherXMLPaser.h"
#import "Weather.h"
#import "WeatherAnnonation.h"
/*
天气预报项目流程
1,POST请求抓起网络数据
2,XML解析response的数据
3,MapView
4,XML返回的地址信息,利用Geocoder地理编码器获得经纬度,设置大头针位置
5,XML中的图片名作大头针annotation的自己定义image
6,大头针的title显示城市名和温度和空气质量PM2.5 PM10
7,大头针的subtitle显示天气详情
*/
@interface MainViewController () <MKMapViewDelegate>
{
// 操作队列
NSOperationQueue *_queue;
// 地图视图
MKMapView *_mapView;
// 地理编码器
CLGeocoder *_geocoder;
}
@end
@implementation MainViewController
/*
在开发网络应用时。通常server考虑到负载的问题,会禁止同一个地址,
连续多次提交请求
大多数这样的情况下,server仅仅响应一次!
解决的方法:隔一秒抓一次。
思路:
1) 抓取城市天气信息的数据,不能够并发运行,要开个新线程,即在background运行
须要依次运行=>NSURLConntection须要发送同步请求
2) 假设单纯使用同步请求,会堵塞主线程,影响用户体验
3) 新开一个线程,在后台依次抓取全部城市的数据
*/
#pragma mark - 实例化视图
- (void)loadView
{
self.view = [[UIView alloc]initWithFrame:[UIScreen mainScreen].applicationFrame];
_mapView = [[MKMapView alloc]initWithFrame:self.view.bounds];
// 1. 假设须要旋转屏幕。同一时候自己主动调整视图大小
[_mapView setAutoresizingMask:UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFlexibleWidth];
// 2. 加入到根视图
[self.view addSubview:_mapView];
// 3. 设置mapView的代理 为当前控制器
[_mapView setDelegate:self];
}
#pragma mark - 载入数据
- (void)viewDidLoad
{
[super viewDidLoad];
_queue = [[NSOperationQueue alloc]init];
_geocoder = [[CLGeocoder alloc]init];
// 在后台线程载入城市数据
[self performSelectorInBackground:@selector(loadWeatherData)
withObject:nil];
}
#pragma mark 自己定义方法,载入城市天气数据。后台运行
- (void)loadWeatherData
{
NSLog(@"%@", [NSThread currentThread]);
[self loadWeatherDataWithCityName:@"北京"];
[NSThread sleepForTimeInterval:1.0f];
[self loadWeatherDataWithCityName:@"重庆"];
[NSThread sleepForTimeInterval:1.0f];
[self loadWeatherDataWithCityName:@"上海"];
}
#pragma mark 自己定义方法,POST请求,抓取网络天气数据
- (void)loadWeatherDataWithCityName:(NSString *)cityName
{
// 1. NSURL
NSString *urlString = @"http://www.webxml.com.cn/WebServices/WeatherWebService.asmx/getWeatherbyCityName";
NSURL *url = [NSURL URLWithString:urlString];
// 2. NSMutableURLRequest,POST请求
NSMutableURLRequest *request = [NSMutableURLRequest
requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:2.0f];
// 1) 指定数据体
NSString *bodyString = [NSString stringWithFormat:@"theCityName=%@",
cityName];
// 中文必须转码 NSUTF8StringEncoding
NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
// 设置请求体
[request setHTTPBody:bodyData];
// 2) 指定http请求方式
[request setHTTPMethod:@"POST"];
// 3. NSURLConnection。同步请求,response用于接收返回的内容
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:nil];
// 1) 实例化单例 天气XML解析器
WeatherXMLPaser *parser = [WeatherXMLPaser sharedWeatherXMLPaser];
// 2) 解析
[parser parserWeatherData:data completion:^(NSArray *dataList) {
// 解析完成的回调方法中,填充Model
Weather *w = [Weather weatherWithArray:dataList];
// 依据城市名称。使用地理编码器获取到相应的经纬度,然后设置大头针的位置
[_geocoder geocodeAddressString:w.cityName
completionHandler:^(NSArray *placemarks, NSError *error) {
// 地标有个location成员,location里面有2D坐标
CLPlacemark *placemark = placemarks[0];
// 大头针安插在此
WeatherAnnonation *annonation = [[WeatherAnnonation alloc]init];
// 指定大头针的经纬度位置
annonation.coordinate = placemark.location.coordinate;
annonation.title = [NSString stringWithFormat:@"%@ %@", w.cityName, w.temperature];
annonation.subtitle = [NSString stringWithFormat:@"%@ %@", w.todayInfo, w.wind];
annonation.imageName = w.imageName;
[_mapView addAnnotation:annonation];
}];
}];
}
#pragma mark - 地图视图代理方法,viewForAnnotation
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id<MKAnnotation>)annotation
{
// 要推断isKindOfClass,假设不是自己定义的,就用默认的,即return nil
// 假设传入的annotation不是自己定义大头针视图。直接返回nil,
// 即使用地图默认的方法绘制大头针
// 假设是自己定义视图。才要设置大头针属性,牢记~~~~
if (![annotation isKindOfClass:[WeatherAnnonation class]]) {
return nil;
}
static NSString *ID = @"ID";
MKAnnotationView *view = [mapView
dequeueReusableAnnotationViewWithIdentifier:ID];
if (view == nil) {
view = [[MKAnnotationView alloc]initWithAnnotation:annotation
reuseIdentifier:ID];
// 设置大头针,能够被点击后呼出
view.canShowCallout = YES;
}
// 设置大头针视图独一无二的属性
// 1) 假设大头针视图是从缓冲池取出的,必须要又一次设置大头针
view.annotation = annotation;
// 设置图像
// 2) 设置大头针图像,需手动转成WeatherAnnonation *,才干使用子类的特有属性
[view setImage:[UIImage imageNamed:((WeatherAnnonation *)annotation).icon]];
return view;
}
@end
H:/1021/03_天气预报_Weather.m
// Weather.m
// 03.天气预报
// Created by apple on 13-10-21.
/*
// Weather.h
// 03.天气预报
#import <Foundation/Foundation.h>
@interface Weather : NSObject
#pragma mark 工厂方法
+ (Weather *)weatherWithArray:(NSArray *)array;
// 1. 城市名
@property (strong, nonatomic) NSString *cityName;
// 2. 今天的信息
@property (strong, nonatomic) NSString *todayInfo;
// 3. 风向
@property (strong, nonatomic) NSString *wind;
// 4. 图片名
@property (strong, nonatomic) NSString *imageName;
// 5. 气温
@property (strong, nonatomic) NSString *temperature;
@end
*/
#import "Weather.h"
@implementation Weather
+ (Weather *)weatherWithArray:(NSArray *)array
{
Weather *w = [[Weather alloc]init];
w.cityName = array[1];
w.todayInfo = array[6];
w.wind = array[7];
w.imageName = array[8];
w.temperature = array[5];
return w;
}
// 重写toString方法
- (NSString *)description
{
return [NSString stringWithFormat:
@"<Weather: %p, cityName: %@, todayInfo: %@, wind: %@,
imageName: %@, temperature: %@>",
self, self.cityName, self.todayInfo,
self.wind, self.imageName, self.temperature];
}
@end
H:/1021/03_天气预报_WeatherAnnonation.h
// WeatherAnnonation.h
// 03.天气预报
// Created by apple on 13-10-21.
// Copyright (c) 2013年 itcast. All rights reserved.
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface WeatherAnnonation : NSObject <MKAnnotation>
// 覆盖协议里面的成员,坐标,标题,副标题,图片名
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (strong, nonatomic) NSString *imageName;
@end
H:/1021/03_天气预报_WeatherXMLPaser.h
// WeatherXMLPaser.h
// 03.天气预报
// Created by apple on 13-10-21.
#import <Foundation/Foundation.h>
/*
定义block代码块,目的是解析完成之后调用
返回值是 void
參数是 数组,里面的每一个成员是一个NSString
*/
typedef void(^WeatherFinishedBlock)(NSArray *dataList);
@interface WeatherXMLPaser : NSObject
// 单例,返回解析器对象
+ (WeatherXMLPaser *)sharedWeatherXMLPaser;
// 解析器解析数据,參数1是要解析的数据,參数2是解析完成回调的代码块
- (void)parserWeatherData:(NSData *)data
completion:(WeatherFinishedBlock)completion;
@end
H:/1021/03_天气预报_WeatherXMLPaser.m
// WeatherXMLPaser.m
// 03.天气预报
// Created by apple on 13-10-21.
/*
天气预报项目流程
1,POST请求抓起网络数据
2,XML解析response的数据
3,MapView
4,XML返回的地址信息,利用Geocoder地理编码器获得经纬度,设置大头针位置
5,XML中的图片名作大头针annotation的自己定义image
6,大头针的title显示城市名和温度和空气质量PM2.5 PM10
7,大头针的subtitle显示天气详情
*/
#import "WeatherXMLPaser.h"
// 单例第1步:静态实例变量
static WeatherXMLPaser *sharedInstance;
// 要想解析XML 必须遵守协议<NSXMLParserDelegate>
@interface WeatherXMLPaser() <NSXMLParserDelegate>
{
// 自己定义block代码块
WeatherFinishedBlock _FinishedBlock;
// 解析结果的字符串数组,根节点是<ArrayOfString>,其余节点名全是<String>
NSMutableArray *_dataList;
// 暂时文本字符串
NSMutableString *_tempStr;
}
@end
@implementation WeatherXMLPaser
/* 单例模板写法
1. 静态实例变量 static WeatherXMLPaser *sharedInstance;
2. allocWithZone
3. shared方法*/
#pragma mark - 单例方法
// 单例第2步:类方法,allocWithZone
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
// 单例,返回解析器对象
// 单例第3步:类方法,shared方法
+ (WeatherXMLPaser *)sharedWeatherXMLPaser
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[WeatherXMLPaser alloc]init];
});
return sharedInstance;
}
#pragma mark - 成员方法
#pragma mark 解析器解析数据,參数1是要解析的数据,參数2是完成时调用的代码块
- (void)parserWeatherData:(NSData *)data
completion:(WeatherFinishedBlock)completion
{
// 0. 记录块代码
_FinishedBlock = completion;
// 1. 实例化XML解析器
NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
// 2. 设置代理为 当前的WeatherXMLPaser
[parser setDelegate:self];
// 3. 解析器開始解析
[parser parse];
}
#pragma mark - XML解析代理方法
#pragma mark 5. 结束解析文档
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// 解析结束,调用代码块,參数是,解析完的NSString数组
// 通过block代码块回调,通知调用方解析结果
_FinishedBlock(_dataList);
}
#pragma mark 2. 開始解析元素节点
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
// 根节点是<ArrayOfString>,其余节点名全是<String>
// 假设节点名是ArrayOfString,说明是根节点,准备好数组_dataList,装数据
if ([elementName isEqualToString:@"ArrayOfString"]) {
if (_dataList) {
[_dataList removeAllObjects];
}
}
// 不管是什么节点開始了,都要将暂时文本清空,用于拼装文本节点
[_tempStr setString:@""];
}
#pragma mark 4. 结束解析节点,重点
- (void)parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
// 根节点是<ArrayOfString>,其余节点名全是<String>
NSString *result = [NSString stringWithString:_tempStr];
// 假设结束的节点是</String>,就把拼装好的文本节点,加入到数组_dataList
if ([elementName isEqualToString:@"string"]) {
[_dataList addObject:result];
}
}
#pragma mark 1. 開始解析文档,初始化准备工作
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
// 懒载入暂时文本字符串
if (_tempStr == nil) {
_tempStr = [NSMutableString string];
}
// 懒载入结果数组
if (_dataList == nil) {
_dataList = [NSMutableArray array];
}
}
#pragma mark 6. 解析出错
- (void)parser:(NSXMLParser *)parser
parseErrorOccurred:(NSError *)parseError
{
NSLog(@"解析出错 %@", parseError.localizedDescription);
// 置空暂时文本
[_tempStr setString:@""];
}
#pragma mark 3. 发现文本内容(一个文本节点可能会解析多次)
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
// 追加文本
[_tempStr appendString:string];
}
@end