トップ 最新 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|12|
2024|01|02|

2015-08-25 [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からどうぞ。
https://github.com/murakami/RFCViewer - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)

トップ 最新 追記