ios的服务器请求管理

之前在做ios项目的时候,要完成客户端向服务器请求并处理数据的功能。期间有遇到一些问题:

1.客户端的服务请求每次都要重新写一个service类对请求进行管理,service类无法重用;

2.在同一个页面会遇到跟服务器交互次数不止一次的问题,这使得client类要对service类的回调中进行判断,使得service类的回调方法实现很长而且越来越难以维护;

3.跟2一样的情况下,请求频繁时会使部分请求被后面的请求覆盖,使得数据丢失;

4.当程序请求的服务器不止一个的时候,原单例的service类不能满足需求,只能再写一个service类。

为解决以上问题,翻了下设计模式的书,写了较为通用的MUNetworkServiceManager,算是一个设计入门的练习,所以也有很多不足或还能继续改进的地方。

引言说完,开始进入正题。

首先设计一个类,这个类是client类跟manager类交互的基础,manager能重用在于MUNetworkPackage类。以下是该类的.h和.m文件

#import <Foundation/Foundation.h>

#define MUUserInfoKeyRequestSourceKey @"MUUserInfoKeyRequestSourceKey"
#define MUUserInfoKeyResponseResultSelectorKey @"MUUserInfoKeyResponseResultSelectorKey"
#define MUUserInfoKeyResponseErrorSelectorKey @"MUUserInfoKeyResponseErrorSelectorKey"

typedef enum
{
    MURequestTypeGet,
    MURequestTypePost,
} MURequestType;

@interface MUNetworkPackage : NSObject

//必须赋值
@property (nonatomic, strong) NSDictionary* userInfo;   //包括来源、获取数据后响应方法和遇到错误响应方法
@property (nonatomic, copy) NSString* requestAddress;
@property (nonatomic, copy) NSString* requestServiceName;

//可选赋值
@property (nonatomic) MURequestType requestType;
@property (nonatomic, strong) NSString* requestPostDataString;
@property (nonatomic) NSStringEncoding encoding;

//扩展
@property (nonatomic, copy) NSString* requestSelectorName;
@property (nonatomic, strong) id requestResult;


- (id)initWithAddress:(NSString*)requestAddress andServiceName:(NSString*)serviceName withUserInfo:(NSDictionary*)userInfo;

@end

#import "MUNetworkPackage.h"

@implementation MUNetworkPackage

@synthesize userInfo = _userInfo, requestAddress = _requestAddress, requestServiceName = _requestServiceName;
@synthesize requestType = _requestType, requestPostDataString = _requestPostDataString, encoding = _encoding;
@synthesize requestSelectorName = _requestSelectorName, requestResult = _requestResult;

- (id)initWithAddress:(NSString*)requestAddress andServiceName:(NSString*)serviceName withUserInfo:(NSDictionary*)userInfo
{
    if (self = [super init]) {
        self.requestAddress = requestAddress;
        self.requestServiceName = serviceName;
        self.userInfo = userInfo;
        
        self.requestType = MURequestTypeGet;
        NSStringEncoding enc = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000); //GBK
        self.encoding = enc;
    }
    return self;
}

@end

以下是设计的简单思路:


每次Client类只需通过Package类跟Manager打交道,使得NetworkService的工作得以封装和下次的重用。其中MUNetworkDefaultService和otherService是MUNetworkService的子类,Manager可以管理不止一个Service,

同时还支持像新浪微博等拥有自己服务器的sdk的扩展。

#import <Foundation/Foundation.h>
#import "MUNetworkService.h"

@interface MUNetworkServiceManager : NSObject
{
    NSMutableDictionary* _serviceManager;
}

+ (MUNetworkServiceManager*)shareInstance;
- (void)registerServiceNames:(NSArray*)registerNames forServiceClassName:(NSString*)className;
- (void)changeServerAddress:(NSString*)serverAddress forServiceName:(NSString*)serviceName;

- (NSInteger)getServiceCount;

- (void)requestWithObject:(MUNetworkPackage*)package;

@end

#import "MUNetworkServiceManager.h"

@implementation MUNetworkServiceManager

static MUNetworkServiceManager* __instance;

+ (MUNetworkServiceManager*)shareInstance
{
    if (!__instance) {
        @synchronized(self) {
            if(!__instance) {
                __instance = [[MUNetworkServiceManager alloc] init];                
            }
        }
    }
    
	return __instance;
}

- (void)registerServiceNames:(NSArray*)registerNames forServiceClassName:(NSString*)className
{
    if (className == nil) {
        className = @"MUNetworkDefaultService";
    }
    if (_serviceManager != nil) 
    {
        [_serviceManager removeAllObjects];
    } else
    {
        _serviceManager = [[NSMutableDictionary alloc] init];
    }
    int i = 0, count = 0;
    count = [registerNames count];
    if (count > 0) {
        for (i = 0; i < count; i++) 
        {
            MUNetworkService* service = [[NSClassFromString(className) alloc] init];    
            [_serviceManager setObject:service forKey:[registerNames objectAtIndex:i]];
        }
    }
}

- (void)changeServerAddress:(NSString*)serverAddress forServiceName:(NSString*)serviceName
{
    MUNetworkService* service = [_serviceManager objectForKey:serviceName];
    service.serverAddress = serverAddress;
}

- (NSInteger)getServiceCount
{
    return [_serviceManager count];
}

- (void)requestWithObject:(MUNetworkPackage*)package
{
    MUNetworkService* service = [_serviceManager objectForKey:package.requestServiceName];
    [service requestWithObject:package];
}

@end

Manager类是个单例。

#import <Foundation/Foundation.h>
#import "MUNetworkHeaders.h"

@interface MUNetworkService : NSObject
{
    BOOL _isBusy;
    MUQueue* _requestQueue;
}

@property (nonatomic, copy) NSString* serverAddress;

- (void)requestWithObject:(MUNetworkPackage*)package;
- (void)didGettingResult:(id) resultData;
- (void)didGettingError:(id) error;

@end

MUQueue是自己实现的一个队列类,拥有队列的一些普通操作。

#import "MUNetworkService.h"

@implementation MUNetworkService

@synthesize serverAddress = _serverAddress;

- (id)init
{
    if (self = [super init]) 
    {
        _isBusy = NO;
        _requestQueue = [[MUQueue alloc] initWithCapacity:5];
    }
    return self;
}

- (void)requestWithObject:(MUNetworkPackage*)package 
{
    
}

- (void)didGettingResult:(id) resultData 
{
    _isBusy = NO;
    MUNetworkPackage* package = (MUNetworkPackage*)resultData;
    NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[package.userInfo objectForKey:MUUserInfoKeyRequestSourceKey], MUCommandRequestSource, [package.userInfo objectForKey:MUUserInfoKeyResponseResultSelectorKey], MUCommandResponseSelcetor, package, MUCommandSelectorParam, nil];
    MUCommand* command = [[MUPerformSelectorCommand alloc] initWithUserInfo:userInfo];
    [command execute];
    
    NSLog(@"left: %d", [_requestQueue count]);
    if (!_isBusy && [_requestQueue count] > 0) 
    {
        [self requestWithObject:[_requestQueue pop]];
    }
}

- (void)didGettingError:(id) error 
{
    _isBusy = NO;
    MUNetworkPackage* package = (MUNetworkPackage*)error;
    NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[package.userInfo objectForKey:MUUserInfoKeyRequestSourceKey], MUCommandRequestSource, [package.userInfo objectForKey:MUUserInfoKeyResponseErrorSelectorKey], MUCommandResponseSelcetor, package, MUCommandSelectorParam, nil];
    MUCommand* command = [[MUPerformSelectorCommand alloc] initWithUserInfo:userInfo];
    [command execute];
    
    if (!_isBusy && [_requestQueue count] > 0) 
    {
        [self requestWithObject:[_requestQueue pop]];
    }
}

@end

通过队列和isBusy标志对请求队列进行管理,requestWithObject:方法在此不实现,留到其子类时再进行实现。MUCommand是一个命令类,保存一个dictionary然后对需要进行的操作方法进行操作。以下是MUNetworkService默认的一个子类,进行普通常见的请求。

#import <Foundation/Foundation.h>
#import "MUNetworkService.h"

@interface MUNetworkDefaultService : MUNetworkService

- (void)requestWithObject:(MUNetworkPackage*)package;

@end

现要实现其requestWithObject:方法。

#import "MUNetworkDefaultService.h"

@implementation MUNetworkDefaultService

- (void)requestWithObject:(MUNetworkPackage*)package 
{    
    if (_isBusy) 
    {
        [_requestQueue push:package];
    } else
    {
        _isBusy = YES;
        if (package.requestType == MURequestTypeGet) 
        {
            [self performSelectorInBackground:@selector(sendGetNetworkInBackground:) withObject:package];
        } else
        {
            [self performSelectorInBackground:@selector(sendPostNetworkInBackground:) withObject:package];
        }        
    }
}

- (void)sendGetNetworkInBackground:(MUNetworkPackage*) package
{
    @autoreleasepool {
        //pool begin
       //进行get请求
    }
}

- (void)sendPostNetworkInBackground:(MUNetworkPackage*) package
{
    @autoreleasepool {
        //pool begin
        //进行post请求
    }
}

@end

进行get或post请求后要去响应父类已完成的didGettingResult:和didGettingError:。
至于otherService则可通过继承或范畴来进行service的扩展,在此不叙述。
好了,说了那么多,那怎么用呢?
首先需对Manager进行初始化,可以在程序载入处或在需要请求的Client类中,

    NSArray* array = [[NSArray alloc] initWithObjects:@"Baidu", nil];
    [[MUNetworkServiceManager shareInstance] registerServiceNames:array forServiceClassName:nil];  

以下是发起请求时的代码:

        NSDictionary* dic = [NSDictionary dictionaryWithObjectsAndKeys:self, MUUserInfoKeyRequestSourceKey, @"testSelector:", MUUserInfoKeyResponseResultSelectorKey, @"warning:", MUUserInfoKeyResponseErrorSelectorKey, nil];
        MUNetworkPackage* bean = [[MUNetworkPackage alloc] initWithAddress:@"http://www.baidu.com/" andServiceName:@"Baidu" withUserInfo:dic];
        [[MUNetworkServiceManager shareInstance] requestWithObject:bean];

请求完毕后需要对数据进行处理,所以对上面dic中的两个方法进行实现,分别是testSelector:和warning:。

- (void)warning:(id)error
{
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Warning" message:@"Error!" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
    [alert show];
}

- (void)testSelector:(id)resultData
{
    MUNetworkPackage* result = (MUNetworkPackage*)resultData;
    NSLog(@"request: %@ \n From %@ \n", result.requestResult, result.requestServiceName);
}

值得一提的是,为了解决第2个问题,每次请求时都要对其userInfo赋值,让每个package都知道完成请求后该找谁干嘛。
以上就是一个小练习,在之后的项目中应该会不断完善~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值