NSInvocationOperation,delegatePattern
Lecture12迄の内容を基に”Presence”アプリケーションを拡張していきます。
AssignmentPresence3になります。
iPhone Application Programming
今迄、作成したソースはhttp://public.me.com/seijit/iPhone/CS193Pから
今回の目標
前回迄は全てMainThreadで通信を行っていました。その為、待ち時間が長く感じられ、ストレスを受けていたのではないかと思います。今回はそのストレスを軽減する為に別Threadで通信を行い、最後にMainThreadの処理を返すように実装を行います。アプリケーションとしては下の図のように自分のStatusをUpdateする画面を用意し、そこからSendできるようにします。
今回は全てを記述するのは大変なので、要点を絞って記載します。
NSInvocationOperationの作成
ViewがLoadされる際にSelector(synchronousLoadsTwitterUsers)を指定してNSInvocationOperationを作成し、それをNSInvocationOperationQueueにAddします。その中で通信部分の処理を行っています。
また、作成時に指定したSelector内部ではSelector(didFinishLoadingTwitterUsersWithResults)を指定してMainThreadに返しています。
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if ([myData count] == 0) {
[self showLoadingIndicators];
[self beginLoadingTwitterUsers];
}
}
- (void)beginLoadingTwitterUsers {
[myData removeAllObjects];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(synchronousLoadsTwitterUsers) object:nil];
[operationQueue addOperation:operation];
[operation release];
}
- (void)synchronousLoadsTwitterUsers {
NSBundle *bundle = [NSBundle mainBundle];
NSArray *twitterUsers = [NSArray arrayWithContentsOfFile:[bundle pathForResource:@"TwitterUsers" ofType:@"plist"]];
for (NSString *userName in twitterUsers){
Person *person = [[Person alloc] initWithPersonName:userName];
if (person)
[myData addObject:person];
[person release];
}
[self performSelectorOnMainThread:@selector(didFinishLoadingTwitterUsersWithResults) withObject:nil waitUntilDone:NO];
}
- (void)didFinishLoadingTwitterUsersWithResults {
[self hideLoadingIndicators];
[self.tableView reloadData];
[self.tableView flashScrollIndicators];
}
delegete Patternの使用
NavigationItemのRightBarButtonItemをクリックするとStatusComposeする画面をModallyに出すようにしています。
- (void)viewDidLoad {
[super viewDidLoad];
UIBarButtonItem *addButton = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemCompose target:self action:@selector(presentModally) ];
self.navigationItem.rightBarButtonItem = addButton;
[addButton release];
}
- (void)presentModally {
StatusComposeViewController *statusController = [[StatusComposeViewController alloc]initWithNibName:@"StatusCompose" bundle:nil];
statusController.delegate = self;
[self presentModalViewController:statusController animated:YES];
[statusController release];
}
この場合、このActionは今回で言うとPersonListViewControllerに実装するわけです。ではこの画面を消すActionはどこに書けばいいのでしょうか?
単純にStatusComposeViewControllerに下のように実装しても消すことはできます。
[self.navigationController dismissModalViewControllerAnimated:YES];
しかし、PresentとDismissするのは同じContorollerからするのが望ましいと言われています。別の操作を行うのにもこの方が操作をしやすいでしょう。
ここでdelegatePatternを使用します。
Protocolの作成
@class StatusComposeViewController;
@protocol StatusComposeViewDelegate
@optional
- (void)statusComposeViewControllerDidFinish:(StatusComposeViewController *)controller;
- (void)statusComposeViewControllerDidCancel:(StatusComposeViewController *)controller;
@end
今回のdelegateの為のProtocolを作成します。
Propertyの追加
@interface StatusComposeViewController : UIViewController {
// 略
id delegate;
}
// 略
@property (nonatomic, assign) id delegate;
// 略
@end
StatusComposeViewControllerにStatusComposeViewDelegateを満たしたid型の属性を追加します。
StatusComposeViewDelegateの実装
StatusComposeViewDelegateのメソッド(statusComposeViewControllerDidFinish:, statusComposeViewControllerDidCancel: )を実装します。
これでStatusComposeViewController側でStatusComposeViewDelegateで実装されたPersonListViewControllerのメソッド(i.e [self.delegate statusComposeViewControllerDidFinish:])を呼べばよいわけです。
これでAssignmentPresence3を終了としたいと思います。
今回作成したソースはhttp://public.me.com/seijit/iPhone/CS193P/Lecture12のPresence5.tar.gzです