使用委托时,需要更好的方法来进行顺序处理

时间:2010-05-13 18:28:41

标签: iphone objective-c cocoa-touch asynchronous delegates

我有一个WebServiceCaller类,它使用NSURLConnection对Web服务进行异步调用。该类提供了一个委托属性,当Web服务调用完成后,它会在委托上调用方法webServiceDoneWithXXX。

可以调用几种Web服务方法,其中两种是GetSummary和GetList。

使用WebServiceCaller的类最初需要摘要和列表,因此它们的编写方式如下:

-(void)getAllData {
    [webServiceCaller getSummary];
}
-(void)webServiceDoneWithGetSummary {
    [webServiceCaller getList];
}
-(void)webServiceDoneWithGetList {
    ...
}

这样可行,但至少有两个问题:

  1. 呼叫在委托中分开 方法所以很难看到 序列一目了然但更多 重要的是很难控制或 修改序列。
  2. 有时我想只调用GetSummary而不是GetList,所以我 然后必须使用丑陋的班级 告诉我的状态变量 webServiceDoneWithGetSummary是否 是否调用GetList。
  3. 假设在GetSummary完成之前无法完成GetList并返回一些用作GetList输入的数据。

    有没有更好的方法来处理这个问题,仍然可以进行异步调用?

    根据Matt Long的回答进行更新:

    使用通知代替委托,看起来我可以通过设置不同的选择器来解决问题#2,具体取决于我是否需要完整序列(GetSummary + GetList)或只是GetSummary。在调用GetSummary时,两个观察者仍将使用相同的通知名称。我必须编写两个单独的方法来处理GetSummaryDone而不是使用单个委托方法(我需要一些类级变量来判断是否要调用GetList)。

    -(void)getAllData {
        [[NSNotificationCenter defaultCenter] addObserver:self
                 selector:@selector(getSummaryDoneAndCallGetList:) 
                     name:kGetSummaryDidFinish object:nil];
        [webServiceCaller getSummary];
    }
    -(void)getSummaryDoneAndCallGetList {
        [NSNotificationCenter removeObserver]
        //process summary data
    
        [[NSNotificationCenter defaultCenter] addObserver:self
                 selector:@selector(getListDone:) 
                     name:kGetListDidFinish object:nil];
        [webServiceCaller getList];
    }
    -(void)getListDone {
        [NSNotificationCenter removeObserver]
        //process list data 
    }
    
    
    -(void)getJustSummaryData {
        [[NSNotificationCenter defaultCenter] addObserver:self
                 selector:@selector(getJustSummaryDone:)     //different selector but
                     name:kGetSummaryDidFinish object:nil];  //same notification name
        [webServiceCaller getSummary];
    }
    -(void)getJustSummaryDone {
        [NSNotificationCenter removeObserver]
        //process summary data
    }
    

    我还没有尝试过这个。它似乎比拥有状态变量和if-then语句更好,但你必须编写更多方法。我仍然没有看到问题1的解决方案。

1 个答案:

答案 0 :(得分:1)

确实,获取Web服务调用的结果是(并且应该是)异步的,但是,您希望调用按顺序进行。一种方法是在调用第二个之前等待第一个完成,并在第一个完成时发布通知。所以,你的第一个请求的in -connectionDidFinishLoading(在你的webServiceCaller中,我假设),将通知发回给你的控制器,告诉它第一个请求成功完成。类似的东西:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [connection release];
    // receivedData is an NSMutableData object we've been appending
    // to in the -didReceiveData delegate. We'll pass it in the
    // notification so we can hand the data off to the next request.
    [[NSNotificationCenter defaultCenter] 
           postNotificationName:kGetSummaryDidFinish object:receivedData];
}

然后,回到您的控制器中,注册该通知:

- (void)viewDidLoad;
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self
             selector:@selector(getSummaryDidFinish:) 
                 name:kGetSummaryDidFinish object:nil];
}

- (void) getSummaryDidFinish:(NSNotification*)notification;
{
    // If you needed the downloaded data, we passed it in
    NSData *data = [notification object];

    // Decide here if you want to call getList or not.
    if (someConditionOfDataObjectIsTrue)
        [webServiceCaller getList];
}

如果你有很多相互等待的电话,它可能会让人感到困惑和难以维护,所以可能会考虑一种设计模式(目前不会想到这一点)。但是,这种方法对我来说效果很好。通知可以帮助您更有意义,因为当您收到符合某些条件的通知时,您可以从控制器调用所有请求。

希望这是有道理的。