初探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

 代碼下載。下節詳細介紹數據解析和網絡編程,反射(運行時)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM