トップ 最新 追記

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|03|04|

2013-10-02 [iOS]RFCViewer(並列処理の管理)

外部とのやり取りを管理する機能として、オートマティズムのコネクタを参考に、独自のカスタマイズを施している。

実際に利用していて分かった事は、個々の処理の実装は様々で、別スレッドから返ってくる場合があるが、それをメインスレッドに戻して、返す共通の機能としての役割があることだ。また、オートマティズムでは結果を通知で返していたが、これだと、要求との対応が弱くなるので、要求との対応を強くしたい場合は、要求時にBlocksを渡して、Blocksで応答する様に工夫してしてみた。

ヘッダーファイルを見てみよう。

#import <Foundation/Foundation.h>
#import "RFCResponseParser.h"
 
extern NSString *ConnectorDidBeginRfc;
extern NSString *ConnectorInProgressRfc;
extern NSString *ConnectorDidFinishRfc;
 
@interface Connector : NSObject
 
@property (assign, readonly, nonatomic, getter=isNetworkAccessing) BOOL networkAccessing;
 
+ (Connector *)sharedConnector;
- (void)rfcIndexWithCompletionHandler:(RFCResponseParserCompletionHandler)completionHandler;
- (void)rfcWithIndex:(NSUInteger)index completionHandler:(RFCResponseParserCompletionHandler)completionHandler;
- (void)cancelWithIndex:(NSUInteger)index;
- (void)cancelAll;
 
@end

リクエストのメソッドにcompletionHandlerというBlocksを渡せるようにして、これは、パーサに覚えさせておいて、処理が終わった際に呼ぶようにしている。

以下の実装部だ。

#import "Connector.h"
 
NSString    *ConnectorDidBeginRfc = @"ConnectorDidBeginRfc";
NSString    *ConnectorInProgressRfc = @"ConnectorInProgressRfc";
NSString    *ConnectorDidFinishRfc = @"ConnectorDidFinishRfc";
 
@interface Connector () 
@property (strong, nonatomic) NSOperationQueue  *queue;
@property (strong, nonatomic) NSMutableArray    *parsers;
- (void)_notifyRfcStatusWithParser:(RFCResponseParser *)parser;
@end
 
@implementation Connector
 
@synthesize queue = _queue;
@synthesize parsers = _parsers;
 
+ (Connector *)sharedConnector
{
    static Connector *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[Connector alloc] init];
    });
	return _sharedInstance;
}
 
- (id)init
{
    DBGMSG(@"%s", __func__);
    self = [super init];
    if (self) {
        _queue = [[NSOperationQueue alloc]init];
        _parsers = [[NSMutableArray alloc] init];
    }
    return self;
}
 
- (void)dealloc
{
    DBGMSG(@"%s", __func__);
    self.queue = nil;
    self.parsers = nil;
}
 
- (BOOL)isNetworkAccessing
{
    return self.parsers.count > 0;
}
 
- (void)rfcIndexWithCompletionHandler:(RFCResponseParserCompletionHandler)completionHandler
{
    DBGMSG(@"%s", __func__);
    [self rfcWithIndex:0 completionHandler:completionHandler];
}
 
- (void)rfcWithIndex:(NSUInteger)index completionHandler:(RFCResponseParserCompletionHandler)completionHandler
{
    DBGMSG(@"%s", __func__);
    BOOL    networkAccessing = self.networkAccessing;
    
    RFCResponseParser   *parser = [[RFCResponseParser alloc] init];
    parser.index = index;
    parser.queue = self.queue;
    parser.delegate = self;
    parser.completionHandler = completionHandler;
    
    [parser parse];
    if (parser.error) {
        NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
        [userInfo setObject:parser forKey:@"parser"];
        [[NSNotificationCenter defaultCenter] postNotificationName:ConnectorDidFinishRfc
                                                            object:self
                                                          userInfo:userInfo];
        if (parser.completionHandler) {
            parser.completionHandler(parser);
        }
        return;
    }
    
    [self.parsers addObject:parser];
    
    if (networkAccessing != self.networkAccessing) {
        [self willChangeValueForKey:@"networkAccessing"];
        [self didChangeValueForKey:@"networkAccessing"];
    }
    
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    [userInfo setObject:parser forKey:@"parser"];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:ConnectorDidBeginRfc object:self userInfo:userInfo];
}
 
- (void)cancelWithIndex:(NSUInteger)index
{
    DBGMSG(@"%s", __func__);
    NSArray *parsers = [self.parsers copy];
    for (RFCResponseParser *parser in parsers) {
        if (parser.index == index) {
            [parser cancel];
            
            NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
            [userInfo setObject:parser forKey:@"parser"];
            
            [[NSNotificationCenter defaultCenter] postNotificationName:ConnectorDidFinishRfc
                                                                object:self
                                                              userInfo:userInfo];
            
            [self willChangeValueForKey:@"networkAccessing"];
            [self.parsers removeObject:parser];
            [self didChangeValueForKey:@"networkAccessing"];
        }
    }
}
 
- (void)cancelAll
{
    DBGMSG(@"%s", __func__);
    for (RFCResponseParser *parser in self.parsers) {
        [parser cancel];
    }
    
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    [userInfo setObject:self.parsers forKey:@"parsers"];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:ConnectorDidFinishRfc object:self userInfo:userInfo];
    
    [self willChangeValueForKey:@"networkAccessing"];
    [self.parsers removeAllObjects];
    [self didChangeValueForKey:@"networkAccessing"];
}
 
- (void)parser:(RFCResponseParser*)parser didReceiveResponse:(NSURLResponse*)response
{
    DBGMSG(@"%s", __func__);
}
 
- (void)parser:(RFCResponseParser *)parser didReceiveData:(NSData *)data
{
    DBGMSG(@"%s", __func__);
}
 
- (void)parserDidFinishLoading:(RFCResponseParser *)parser
{
    DBGMSG(@"%s", __func__);
    if ([self.parsers containsObject:parser]) {
        [self _notifyRfcStatusWithParser:parser];
    }
}
 
- (void)parser:(RFCResponseParser *)parser didFailWithError:(NSError*)error
{
    DBGMSG(@"%s", __func__);
    if ([self.parsers containsObject:parser]) {
        [self _notifyRfcStatusWithParser:parser];
    }
}
 
- (void)parserDidCancel:(RFCResponseParser *)parser
{
    DBGMSG(@"%s", __func__);
    if ([self.parsers containsObject:parser]) {
        [self _notifyRfcStatusWithParser:parser];
    }
}
 
- (void)_notifyRfcStatusWithParser:(RFCResponseParser *)parser
{
    DBGMSG(@"%s", __func__);
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    [userInfo setObject:parser forKey:@"parser"];
    
    [[NSNotificationCenter defaultCenter] postNotificationName:ConnectorDidFinishRfc
                                                        object:self
                                                      userInfo:userInfo];
    if (parser.completionHandler) {
        parser.completionHandler(parser);
    }
    
    [self willChangeValueForKey:@"networkAccessing"];
    [self.parsers removeObject:parser];
    [self didChangeValueForKey:@"networkAccessing"];
}
 
@end

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/RFCViewer - GitHub

_ 【Cocoa練習帳】

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

2013-10-19 関東第62回Cocoa勉強会

第62回のCocoa勉強会(関東)が開催された。内容は、以下のとおり。

日時
2013/10/19(土) 13:00〜18:00
会場
水道橋 貸し会議室 内海 101会議室
集合
現地
会費
500円
  • 「新しい通信クラス群NSURLSessionを使ってみる」iOS
  • 「APIを前方互換に拡張する」General
  • 「RFC Viewerの紹介」iOS
  • 「ClangのModulesについて」tool
  • 「Cocoaでマルチウインドウ」Mac
  • 「古いシミュレータの捨て方」iOS

前回の勉強会で、NSURLConnectionにQueueを設定して主スレッド以外で動作させる方法を知り、早速、活用して喜んでいたのだが、NSURLSessionによって、もはや、過去のお話になってしまった事を知ってしまった。早速、活用してみよう。

APIの前方互換について、まだ、必要に迫られた事はないが、次のプロジェクトに必要になる可能性があるので復習を。

CloagのModules、ちょうど、フレームワークを作っているので、考慮してみよう。

Cocoaでマルチウィンドウ。最近、OS Xアプリケーションを作っていないので、作りたくなってきました。

古いシミュレータの捨て方、自分の環境を確認してみたところ、キャッシュにゴミが残っていた!これは助かる情報だ。

次回は、12月7日に松戸で開催予定だ。

_ 【Cocoa練習帳】

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

トップ 最新 追記