初探iOS网络开发,数据解析。

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

通过大众点评平台开发来简单了解一下,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

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

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航