IOS

H:/1021/00_block回调.h
/*通过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,类方法,allocWithZone3,类方法,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 MKCoordinateRegionMakeWithDistance4. 添加大头针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生成大头针 annotationMyAnnotation *annotation = [[MyAnnotation alloc]initWithCoordinate:coord title:@"我的地盘" subtitle:nil];// 自定义大头针,可以通过setter方法生成大头针 annotation2MyAnnotation2 *annotation = [[MyAnnotation2 alloc]init];[annotation setCoordinate:coord];[annotation setTitle:@"我的地盘"];[annotation setIcon:@"head0.png"];NSLog(@"%p %@", annotation, annotation);// 添加大头针到mapView[_mapView addAnnotation:annotation];// 自定义大头针,可以通过setter方法生成大头针 annotation2MyAnnotation2 *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 *)mapViewdidUpdateUserLocation:(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 *)mapViewviewForAnnotation:(id<MKAnnotation>)annotation
{// 如果传入的annotation不是自定义大头针视图,直接返回nil,// 即使用地图默认的方法绘制大头针// 如果是自定义视图,才要设置大头针属性,牢记~~~~if (![annotation isKindOfClass:[MyAnnotation2 class]]) {return nil;}// 同cell,标准优化代码static NSString *ID = @"ID";MKAnnotationView *view = [mapViewdequeueReusableAnnotationViewWithIdentifier:ID];// 如果没有找到可重用的大头针视图,才实例化新的if (view == nil) {view = [[MKAnnotationView alloc]initWithAnnotation:annotationreuseIdentifier: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)coordinatetitle:(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指向的是一个新开的地址,故结果依然是oldValueNSLog(@"%@ %@ %@", 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 *)locationcompletionHandler:(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 *)managerdidUpdateLocations:(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,MapView4,XML返回的地址信息,利用Geocoder地理编码器获得经纬度,设置大头针位置5,XML中的图片名作大头针annotation的自定义image6,大头针的title显示城市名和温度和空气质量PM2.5 PM107,大头针的subtitle显示天气详情
*/
@interface MainViewController () <MKMapViewDelegate>
{// 操作队列NSOperationQueue    *_queue;// 地图视图MKMapView           *_mapView;// 地理编码器CLGeocoder          *_geocoder;
}
@end
@implementation MainViewController
/*在开发网络应用时,通常服务器考虑到负载的问题,会禁止同一个地址,连续多次提交请求大多数这种情况下,服务器只响应一次!解决办法:隔一秒抓一次!思路: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. NSURLNSString *urlString = @".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];// 中文必须转码 NSUTF8StringEncodingNSData *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) {// 解析完成的回调方法中,填充ModelWeather *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,MapView4,XML返回的地址信息,利用Geocoder地理编码器获得经纬度,设置大头针位置5,XML中的图片名作大头针annotation的自定义image6,大头针的title显示城市名和温度和空气质量PM2.5 PM107,大头针的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. allocWithZone3. 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 *)elementNamenamespaceURI:(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>,就把拼装好的文本节点,添加到数组_dataListif ([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