iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
ずっと利用し続けている『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;
}