zoukankan      html  css  js  c++  java
  • IOS_地图_定位_天气预报_Block回调_单例

    版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/u012576807/article/details/30362767
    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,类方法,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
    

  • 相关阅读:
    Git for windows(Msysgit)中文乱码
    DB2嵌入式编程,语句“EXEC SQL INCLUDE”说明
    《DB2 最佳实践: 性能调优和问题诊断最佳实践,第 1 部分》阅读笔记
    android sdk setup时出现:Failed to fetch URL...
    Git GUI启动报错问题记录
    安全快门
    在VFP6中模拟CursorAdapter的功能
    调试asp.net网页时不显示treeview的原因
    XP机器上WCF采用X509证书加密时IIS读取证书的授权
    在SQLSERVER2008中建立数据库复制碰到的问题
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10883540.html
Copyright © 2011-2022 走看看