[iOS]Connector/ResponseParserパターンの改良 | Cocoa練習帳

[iOS]Connector/ResponseParserパターンの改良

ずっと利用し続けている『iOS開発におけるパターンによるオートマティズム』のConnector/ResponseParserパターンに独自の改良を施したので説明する。説明の材料となるとは、以前から公開していたRFCViewerだ。


Connector/ResponseParserパターンで課題と考えていたのは、ResponseParserの種類が増えるたびにConnectorに手を加えないといけないことと、Connectorに記述するResponseParser関連のコードは、似た内容になるのだが、共通化出来ないことだ。


ResponseParserは多種多様になるので、今回の改良が全ての場合に適用できるかは、その状況にならないと分からないが、今回、以下の方法で共通化してみた。


ResponseParserの共通の定義をプロトコルとし、ConnecterはResponseParserプロトコルを扱うようにする。ResponseParserプロトコルの定義は以下のとおり。


@protocol ResponseParserProtocol;
 
#define kResponseParserNoError       0
#define kResponseParserGenericError  1
 
typedef enum _ResponseParserNetworkState {
    ResponseParserNetworkSateNotConnected = 0,
    ResponseParserNetworkSateInProgress,
    ResponseParserNetworkSateFinished,
    ResponseParserNetworkSateError,
    ResponseParserNetworkSateCanceled,
} ResponseParserNetworkSate;
 
typedef void (^ResponseParserCompletionHandler)(id<ResponseParserProtocol> parser);
 
@protocol ResponseParserDelegate <NSObject>
- (void)parser:(id<ResponseParserProtocol>)parser didReceiveResponse:(NSURLResponse*)response;
- (void)parser:(id<ResponseParserProtocol>)parser didReceiveData:(NSData *)data;
- (void)parserDidFinishLoading:(id<ResponseParserProtocol>)parser;
- (void)parser:(id<ResponseParserProtocol>)parser didFailWithError:(NSError*)error;
- (void)parserDidCancel:(id<ResponseParserProtocol>)parser;
@end
 
@protocol ResponseParserProtocol <NSObject>
 
@property (assign, readonly, nonatomic) ResponseParserNetworkSate   networkState;
@property (strong, nonatomic) NSError                               *error;
@property (strong, nonatomic) NSOperationQueue                      *queue;
@property (weak, nonatomic) id<ResponseParserDelegate>              delegate;
@property (copy, nonatomic) ResponseParserCompletionHandler         completionHandler;
 
- (void)parse;
- (void)cancel;
 
@end

Connecterの要求メソッドも、要求の種類を辞書型にすることによって、共通化できた。


extern NSString * const ConnectorDidBegin;
extern NSString * const ConnectorInProgress;
extern NSString * const ConnectorDidFinish;
extern NSString * const ConnectorParser;
extern NSString * const ConnectorParsers;
extern NSString * const ConnectorNetworkAccessing;
 
extern NSString * const ConnectorRequestTypeKey;
extern NSString * const ConnectorRequestTypeRFCIndex;
extern NSString * const ConnectorRequestTypeRFC;
 
extern NSString * const ConnectorRFCIndexKey;
 
@interface Connector : NSObject
 
@property (assign, readonly, nonatomic, getter=isNetworkAccessing) BOOL networkAccessing;
 
+ (Connector *)sharedConnector;
- (void)requestWithParams:(NSDictionary *)params completionHandler:(ResponseParserCompletionHandler)completionHandler;
- (void)cancelWithResponseParser:(id<ResponseParserProtocol>)aParser;
- (void)cancelWithParams:(NSDictionary *)params;
- (void)cancelAll;
 
@end

ただ、ConnectorでResponseParserを生成するメソッドの共通化は無理で、ここだけ、ResponseParserの種類が増えるたびに修正という事になる。


- (id<ResponseParserProtocol>)_parserWithParams:(NSDictionary *)params
                                          queue:(NSOperationQueue *)queue
                                       delegate:(id<ResponseParserDelegate>)delegate
                              completionHandler:(ResponseParserCompletionHandler)completionHandler
{
    id<ResponseParserProtocol> parser = nil;
    
    if (params) {
        NSString    *request = params[ConnectorRequestTypeKey];
        if (request && [request isEqualToString:ConnectorRequestTypeRFCIndex]) {
            RFCResponseParser *rfcResponseParser = [[RFCResponseParser alloc] init];
            rfcResponseParser.index = 0;
            rfcResponseParser.queue = self.queue;
            rfcResponseParser.delegate = self;
            rfcResponseParser.completionHandler = completionHandler;
            parser = rfcResponseParser;
        }
        else if (request && [request isEqualToString:ConnectorRequestTypeRFC]) {
            RFCResponseParser *rfcResponseParser = [[RFCResponseParser alloc] init];
            NSUInteger  index = 1;
            NSNumber    *indexNumber = params[ConnectorRFCIndexKey];
            if (indexNumber && [indexNumber isKindOfClass:[NSNumber class]]) {
                index = indexNumber.unsignedIntegerValue;
            }
            rfcResponseParser.index = index;
            rfcResponseParser.queue = self.queue;
            rfcResponseParser.delegate = self;
            rfcResponseParser.completionHandler = completionHandler;
            parser = rfcResponseParser;
        }
    }
    return parser;
}

ソースコード
GitHubからどうぞ。

関連情報
【Cocoa練習帳】
http://ameblo.jp/bitz/(ミラー・サイト)