zoukankan      html  css  js  c++  java
  • 初探iOS网络开发,数据解析。

      通过大众点评平台开发来简单了解一下,oc的网络编程和数据解析(json)

    首先我们需要到大大众点评开发者平台申请一个key。http://developer.dianping.com/app/tech/api这个网站有api文档。

    本文没有使用第三方库,网络其请求使用NSURLConnection类,json数据解析使用NSJSONSerialization。这个例子是根据条件获取商户信息。

    1.定义常量

    #define kSearchResto @"v1/business/find_businesses"
    
    #define kDPDomain @"http://api.dianping.com/"
    
    #define kDPAppKey @"。。。"
    
    #define kDPAppSecret @"。。。"
    
    #define kWFRequestimeOutInterval 60.0
    
    #define kHttpMethodGET @"GET"
    
    #define kHttpMethodPOST @"POST"
    

     2.创建数据类,包含商户信息

    //
    //  WFBusiness.h
    //  WFSearch
    //
    //  Created by ForrestWoo on 14-9-5.
    //  Copyright (c) 2014年 ForrestWoo. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    #import "WFRootModel.h"
    
    @interface WFBusiness : WFRootModel
    
    @property (nonatomic, assign) int business_id;
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, strong) NSString *branch_name;
    @property (nonatomic, strong) NSString *address;
    @property (nonatomic, strong) NSString *telephone;
    @property (nonatomic, strong) NSString *city;
    //星级图片链接。
    @property (nonatomic, strong) NSString *rating_img_url;
    @property (nonatomic, strong) NSString *rating_s_img_url;
    @property (nonatomic, strong) NSArray *regions;
    @property (nonatomic, strong) NSArray *categories;
    
    //经纬度信息
    @property (nonatomic, assign) float latitude;
    @property (nonatomic, assign) float longitude;
    @property (nonatomic, assign) float avg_rating;
    @property (nonatomic, assign) float product_score;
    @property (nonatomic, assign) float decoration_score;
    @property (nonatomic, assign) float service_score;
    
    //评价 分五种。1:一般,2:尚可,3:好,4:很好,5:非常好
    @property (nonatomic, assign) int product_grade;
    @property (nonatomic, assign) int decoration_grade;
    @property (nonatomic, assign) int service_grade;
    
    //人均消费。
    @property (nonatomic, assign) int avg_price;
    //点评。
    @property (nonatomic, assign) int review_count;
    @property (nonatomic, strong) NSArray *review_list_url;
    @property (nonatomic, assign) int distance;
    @property (nonatomic, strong) NSString *business_url;
    
    //图片
    @property (nonatomic, strong) NSString *photo_url;
    @property (nonatomic, strong) NSString *s_photo_url;
    @property (nonatomic, assign) int photo_count;
    @property (nonatomic, strong) NSArray *photo_list_url;
    
    //优惠券。
    @property (nonatomic, assign) int has_coupon;
    @property (nonatomic, assign) int coupon_id;
    @property (nonatomic, strong) NSString *coupon_description;
    @property (nonatomic, strong) NSString *coupon_url;
    
    //团购信息。
    @property (nonatomic, assign) int has_deal;
    @property (nonatomic, assign) int deal_count;
    @property (nonatomic, strong) NSArray *deals;
    @property (nonatomic, strong) NSString *deals_id;
    @property (nonatomic, strong) NSString *deals_description;
    @property (nonatomic, strong) NSString *deals_url;
    @property (nonatomic, assign) int has_online_reservation;
    @property (nonatomic, strong) NSString *online_reservation_url;
    
    - (id)initWithJson:(NSDictionary *)jsonData;
    
    @end
    

     这里的属性名字并不是随便定义的,而是根据服务器端返回的字段名称定义的,它与返回的名称是一致的,目的是方便以后通过反射对类的属性赋值,这样我们不需要一一赋值,详情请继续

    3.WFRootModel

    #import <Foundation/Foundation.h>
    
    //根类,定义一些通用的属性和消息
    @interface WFRootModel : NSObject
    
    //获取类的属性名称,以通过反射对对象的属性赋值。
    - (NSArray *)PropertyKeys;
    
    @end
    
    
    #import "WFRootModel.h"
    #import <objc/runtime.h>
    
    @implementation WFRootModel
    
    - (NSArray *)PropertyKeys
    {
        unsigned int outCount,i;
        objc_property_t *pp = class_copyPropertyList([self class], &outCount);
        NSMutableArray *keys = [[NSMutableArray alloc] initWithCapacity:0];
        for (i = 0; i < outCount; i++)
        {
            objc_property_t property = pp[i];
            NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
            [keys addObject:propertyName];
        }
        
        return keys;
    }
    
    @end

      此类赋予了它的子类一个重要行为,它只包含一个消息[- (NSArray *)PropertyKeys],它的作用是子类能够获取自己包含的所有属性。反射中会使用这些属性。

    4.创建请求url

      大众点评请求使用SHA加密。

    [1]SHA加密类SHA1,需要引入

    CommonDigest.h
    @interface SHA1 : NSObject
    
    + (NSString *)getSHAString:(NSData *)aStringbytes;
    
    @end
    
    #import <CommonCrypto/CommonDigest.h>
    
    #import "SHA1.h"
    
    @implementation SHA1
    
    + (NSString *)getSHAString:(NSData *)aStringbytes
    {
        unsigned char digest[CC_SHA1_DIGEST_LENGTH];
        
        if (CC_SHA1([aStringbytes bytes], [aStringbytes length], digest))
        {
            NSMutableString *digestString = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH];
            for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
            {
                unsigned char aChar = digest[i];
                [digestString appendFormat:@"%02x",aChar];
            }
            return digestString;
        }
        else
        {
            return nil;
        }
    }
    
    @end
    

     由于我对加密了解很少,所以就不做介绍了,只给出一个方法,供大家参考。

    [2]返回根url,因为根url会常用到,我们就将它封装起来,以便后用

    - (NSString *)getRootURL
    {
        return kDPDomain;
    }
    

     [3]返回合法的url

    - (NSString *)serializeURL:(NSString *)aBaseURL params:(NSDictionary *)aParams
    {
    	NSURL* parsedURL = [NSURL URLWithString:[aBaseURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    	NSMutableDictionary *paramsDic = [NSMutableDictionary dictionaryWithDictionary:[self parseQueryString:[parsedURL query]]];
    	if (aParams) {
    		[paramsDic setValuesForKeysWithDictionary:aParams];
    	}
    	
    	NSMutableString *signString = [NSMutableString stringWithString:kDPAppKey];
    	NSMutableString *paramsString = [NSMutableString stringWithFormat:@"appkey=%@", kDPAppKey];
    	NSArray *sortedKeys = [[paramsDic allKeys] sortedArrayUsingSelector: @selector(compare:)];
    	for (NSString *key in sortedKeys) {
    		[signString appendFormat:@"%@%@", key, [paramsDic objectForKey:key]];
    		[paramsString  appendFormat:@"&%@=%@", key, [paramsDic objectForKey:key]];
    	}
        NSString *str = kDPAppSecret;
    	[signString appendString:str];
    	NSData *stringBytes = [signString dataUsingEncoding: NSUTF8StringEncoding];
        NSString *digestString = [SHA1 getSHAString:stringBytes];
        if (digestString)
        {
            [paramsString appendFormat:@"&sign=%@", [digestString uppercaseString]];
            NSLog(@"...%@...", [NSString stringWithFormat:@"%@://%@%@?%@", [parsedURL scheme], [parsedURL host], [parsedURL path], [paramsString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]);
    		return [NSString stringWithFormat:@"%@://%@%@?%@", [parsedURL scheme], [parsedURL host], [parsedURL path], [paramsString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
        else
        {
            return nil;
        }
    }
    

     5.创建网络连接,发送请求

    使用NSURLConnection来完成网络连接

    - (void)createConnectionWithUrl:(NSString *)urlString params:(NSDictionary *)aParams delegate:(id<WFRequestDelegate>)aDelegate
    {
        NSString *urlStr = [self serializeURL:[self generateFullURL:urlString] params:aParams];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kWFRequestimeOutInterval];
        
        [request setHTTPMethod:kHttpMethodGET];
        NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
        self.delegate = aDelegate;
    //    [[[self class] sharedInstance] setConnections:conn];
    }
    

     6.返回结果以及数据解析

    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        _responseData = [[NSMutableData alloc] init];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        [_responseData appendData:data];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        NSError *error = nil;
        id result= [NSJSONSerialization JSONObjectWithData:_responseData options:NSJSONReadingAllowFragments error:&error];
        if (!result)
        {
            NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:error,@"error", nil];
            NSError *err = [NSError errorWithDomain:@"domain is error" code:-1 userInfo:userInfo];
            if ([self.delegate respondsToSelector:@selector(request:didfailWithError:)])
            {
                [self.delegate request:self didfailWithError:err];
            }
        }
        else
        {
            NSString *status = 0;
            if ([result isKindOfClass:[NSDictionary class]])
            {
                status = [result objectForKey:@"status"];
            }
            
            if ([status isEqualToString:@"OK"])
            {
                if ([self.delegate respondsToSelector:@selector(request:didfinishloadingWithResult:)])
                {
                    [self.delegate request:self didfinishloadingWithResult:result == nil ?
                                     _responseData : result];
                }
            }
            else
            {
                if ([status isEqualToString:@"ERROR"])
                {
                    //TODO:错误处理代码。
                }
            }
        }
    
    //    NSString *str = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
    //    NSLog(@"_responseData:%@", str);
        
    //    [self clearData];
    }
    
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        NSLog(@"ERROR!%@", error.description);
    }
    

     返回的数据存储在一个WFFindBusinessesResult的实例中。

    //super class for result.
    @interface WFUrlResult : NSObject
    
    @property (nonatomic, strong) NSString *status;
    @property (nonatomic, assign) NSInteger total_count;
    @property (nonatomic, assign) NSInteger count;
    
    - (id)initWithJson:(NSDictionary *)jsonData;
    
    @end
    
    
    @interface WFFindBusinessesResult : WFUrlResult
    
    @property (nonatomic, strong) NSArray *businesses;
    
    @end
    

     对对象赋值非常简单

    @implementation WFFindBusinessesResult
    
    - (id)initWithJson:(NSDictionary *)jsonData
    {
        
        self.status = [jsonData objectForKey:@"status"];
        self.count = [[jsonData objectForKey:@"count"] integerValue];
        self.total_count = [[jsonData objectForKey:@"total_count"] integerValue];
        NSArray *arr = nil;
        NSMutableArray *businessArr = [[NSMutableArray alloc] initWithCapacity:0];
        
        if ([jsonData isKindOfClass:[NSDictionary class]])
        {
            arr = [jsonData objectForKey:@"businesses"];
        //赋值,通过反射赋值,根本不需要一一对字段赋值。 for (id obj in arr) { WFBusiness *bus = [[WFBusiness alloc] init]; NSArray *propertyList = [[[WFBusiness alloc] init] PropertyKeys]; for (NSString *key in propertyList) { [bus setValue:[obj objectForKey:key] forKey:key]; } [businessArr addObject:bus]; NSLog(@"photo is %@", [bus categories]); } } NSLog(@"businessArr count is %lu", [businessArr count]); self.Businesses = businessArr; return self; } @end

     完整的封装类WFHTTPRequest。它用于创建一个连接,并发送请求,管理整个应用出现的网络连接,创建一个单例,全局唯一。

    //
    //  WFRequest.h
    //  WFSearch
    //
    //  Created by ForrestWoo on 14-8-30.
    //  Copyright (c) 2014年 ForrestWoo. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @class WFHTTPRequest;
    @protocol WFRequestDelegate <NSObject>
    
    @optional
    - (void)request:(WFHTTPRequest *)request didfinishloadingWithResult:(id)aResult;
    - (void)request:(WFHTTPRequest *)request didfailWithError:(NSError *)aError;
    
    @end
    
    @interface WFHTTPRequest : NSObject
    
    @property (nonatomic, unsafe_unretained) id<WFRequestDelegate> delegate;
    @property (nonatomic, strong) NSString *aUrl;
    @property (nonatomic, strong) NSDictionary *aParams;
    @property (nonatomic, strong) NSArray *connections;
    
    + (WFHTTPRequest *)sharedInstance;
    
    - (void)createConnectionWithUrl:(NSString *)urlString params:(NSDictionary *)aParams delegate:(id<WFRequestDelegate>)aDelegate;
    
    - (void) cancel;
    - (NSString *)getRootURL;
    
    
    
    //api
    
    - (void)findBusinessesWithParams:(NSDictionary *)aParams delegate:(id<WFRequestDelegate>)aDelegate;
    - (void)findCityWithDelegate:(id<WFRequestDelegate>)aDelegate;
    - (void)getCategoriesForBusinessesWithDelegate:(id<WFRequestDelegate>)aDelegate;
    
    @end
    
    //
    //  WFRequest.m
    //  WFSearch
    //
    //  Created by ForrestWoo on 14-8-30.
    //  Copyright (c) 2014年 ForrestWoo. All rights reserved.
    //
    
    #import "WFHTTPRequest.h"
    #import "WFConstants.h"
    #import "SHA1.h"
    
    @interface WFHTTPRequest () <NSURLConnectionDataDelegate>
    
    //- (void)appendUTF8Body:(NSMutableData *)aBody dataString:(NSString *)aDataString;
    //- (NSDictionary *)parseQueryString:(NSString *)query;
    ////- (void)handleResponseData:(NSData *)data;
    //- (NSString *)generateFullURL:(NSString *)url;
    ////- (void)addConnection;
    //- (NSString *)serializeURL:(NSString *)aBaseURL params:(NSDictionary *)aParams;
    
    @end
    
    static WFHTTPRequest *sharedObj = nil;
    
    @implementation WFHTTPRequest
    {
        NSURLConnection *_connection;
        NSMutableData *_responseData;
    }
    
    - (NSString *)getRootURL
    {
        return kDPDomain;
    }
    
    - (NSString *)generateFullURL:(NSString *)url
    {
        NSMutableString *str = [[NSMutableString alloc] initWithCapacity:0];
        
        [str appendString:[self getRootURL]];
        [str appendString:url];
        return str;
    }
    
    + (WFHTTPRequest *)sharedInstance
    {
        static dispatch_once_t pred = 0;
        
        dispatch_once(&pred, ^{
            sharedObj = [[super allocWithZone:NULL] init];
        });
    
        return sharedObj;
    }
    
    + (id)allocWithZone:(struct _NSZone *)zone
    {
        return [self sharedInstance];
    }
    
    - (void)createConnectionWithUrl:(NSString *)urlString params:(NSDictionary *)aParams delegate:(id<WFRequestDelegate>)aDelegate
    {
        NSString *urlStr = [self serializeURL:[self generateFullURL:urlString] params:aParams];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kWFRequestimeOutInterval];
        
        [request setHTTPMethod:kHttpMethodGET];
        NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
        self.delegate = aDelegate;
    //    [[[self class] sharedInstance] setConnections:conn];
    }
    
    - (void)findBusinessesWithParams:(NSDictionary *)aParams delegate:(id<WFRequestDelegate>)aDelegate
    {
        [self createConnectionWithUrl:kSearchResto params:aParams delegate:aDelegate];
    }
    
    - (void)findCityWithDelegate:(id<WFRequestDelegate>)aDelegate
    {
        [self createConnectionWithUrl:kSearchCity params:nil delegate:aDelegate];
    }
    
    - (void)getCategoriesForBusinessesWithDelegate:(id<WFRequestDelegate>)aDelegate
    {
        [self createConnectionWithUrl:kCategoriesWithBusinesses params:nil delegate:aDelegate];
    }
    
    //- (void)appendUTF8Body:(NSMutableData *)aBody dataString:(NSString *)aDataString
    //{
    //    [aBody appendData:[aDataString dataUsingEncoding:NSUTF8StringEncoding]];
    //}
    
    - (NSDictionary *)parseQueryString:(NSString *)query
    {
        NSMutableDictionary *paramDict = [[NSMutableDictionary alloc] initWithDictionary:0];
        
        NSArray *paramArr = [query componentsSeparatedByString:@"&"];
        for (NSString *param in paramArr)
        {
            NSArray * elements = [param componentsSeparatedByString:@"="];
            if ([elements count] <= 1)
            {
                return nil;
            }
            
            NSString *key = [[elements objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            NSString *value = [[elements objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            
            [paramDict setObject:value forKey:key];
        }
        
        return paramDict;
    }
    
    - (NSString *)serializeURL:(NSString *)aBaseURL params:(NSDictionary *)aParams
    {
    	NSURL* parsedURL = [NSURL URLWithString:[aBaseURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    	NSMutableDictionary *paramsDic = [NSMutableDictionary dictionaryWithDictionary:[self parseQueryString:[parsedURL query]]];
    	if (aParams) {
    		[paramsDic setValuesForKeysWithDictionary:aParams];
    	}
    	
    	NSMutableString *signString = [NSMutableString stringWithString:kDPAppKey];
    	NSMutableString *paramsString = [NSMutableString stringWithFormat:@"appkey=%@", kDPAppKey];
    	NSArray *sortedKeys = [[paramsDic allKeys] sortedArrayUsingSelector: @selector(compare:)];
    	for (NSString *key in sortedKeys) {
    		[signString appendFormat:@"%@%@", key, [paramsDic objectForKey:key]];
    		[paramsString  appendFormat:@"&%@=%@", key, [paramsDic objectForKey:key]];
    	}
        NSString *str = kDPAppSecret;
    	[signString appendString:str];
    	NSData *stringBytes = [signString dataUsingEncoding: NSUTF8StringEncoding];
        NSString *digestString = [SHA1 getSHAString:stringBytes];
        if (digestString)
        {
            [paramsString appendFormat:@"&sign=%@", [digestString uppercaseString]];
            NSLog(@"...%@...", [NSString stringWithFormat:@"%@://%@%@?%@", [parsedURL scheme], [parsedURL host], [parsedURL path], [paramsString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]);
    		return [NSString stringWithFormat:@"%@://%@%@?%@", [parsedURL scheme], [parsedURL host], [parsedURL path], [paramsString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
        }
        else
        {
            return nil;
        }
    }
    
    - (void) cancel
    {
        [_connection cancel];
    }
    
    + (NSString *)getParamValueFromURL:(NSString *)aURl paramName:(NSString *)aParamName
    {
        return nil;
    }
    
    #pragma mark - NSURLConnection Delegate Methods
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        _responseData = [[NSMutableData alloc] init];
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
        [_responseData appendData:data];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        NSError *error = nil;
        id result= [NSJSONSerialization JSONObjectWithData:_responseData options:NSJSONReadingAllowFragments error:&error];
        if (!result)
        {
            NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:error,@"error", nil];
            NSError *err = [NSError errorWithDomain:@"domain is error" code:-1 userInfo:userInfo];
            if ([self.delegate respondsToSelector:@selector(request:didfailWithError:)])
            {
                [self.delegate request:self didfailWithError:err];
            }
        }
        else
        {
            NSString *status = 0;
            if ([result isKindOfClass:[NSDictionary class]])
            {
                status = [result objectForKey:@"status"];
            }
            
            if ([status isEqualToString:@"OK"])
            {
                if ([self.delegate respondsToSelector:@selector(request:didfinishloadingWithResult:)])
                {
                    [self.delegate request:self didfinishloadingWithResult:result == nil ?
                                     _responseData : result];
                }
            }
            else
            {
                if ([status isEqualToString:@"ERROR"])
                {
                    //TODO:错误处理代码。
                }
            }
        }
    
    //    NSString *str = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
    //    NSLog(@"_responseData:%@", str);
        
    //    [self clearData];
    }
    
    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
    {
        NSLog(@"ERROR!%@", error.description);
    }
    
    - (void)clearData
    {
        _responseData = nil;
        [_connection cancel];
        _connection = nil;
    }
    @end
    

     代码下载。下节详细介绍数据解析和网络编程,反射(运行时)

  • 相关阅读:
    Lake Counting
    部分和问题
    迷宫最短路
    sublime 的使用技巧
    数组
    Factorial Trailing Zeroes
    Top K Frequent Elements
    Number of Connected Component in An Undirected Graph
    Zigzag Iterator
    Single Number III
  • 原文地址:https://www.cnblogs.com/salam/p/4348338.html
Copyright © 2011-2022 走看看