/var/log/seiji

13 Dec 2008

NSInvocationOperation,delegatePattern-CS193P

NSInvocationOperation,delegatePattern

Lecture12迄の内容を基に"Presence"アプリケーションを拡張していきます。 AssignmentPresence3になります。
CS193P - Cocoa Programming | Announcements.jpg
iPhone Application Programming

今迄、作成したソースはhttp://public.me.com/seijit/iPhone/CS193Pから

今回の目標

前回迄は全てMainThreadで通信を行っていました。その為、待ち時間が長く感じられ、ストレスを受けていたのではないかと思います。今回はそのストレスを軽減する為に別Threadで通信を行い、最後にMainThreadの処理を返すように実装を行います。アプリケーションとしては下の図のように自分のStatusをUpdateする画面を用意し、そこからSendできるようにします。

Presence-Part3-1-1.jpg

今回は全てを記述するのは大変なので、要点を絞って記載します。

picture.pngNSInvocationOperationの作成

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];
}

picture.pngdelegete 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です

Comments

comments powered by Disqus