我有一个简单的类,它公开了一种方法,该方法进行多个服务器调用以获取对象ID列表的对象数据。该方法枚举对象ID列表并进行单个服务器调用,如下所示...
@implementation MyClass - (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs { typeof(self) __weak blockSelf = self; for(NSString *objectID in objectIDs) { [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{ if(objectID == [objectIDs lastObject]) { //<---will this work? [blockSelf.delegate finishedFetching]; } }]; } } - (void)fetchObjectDataForObjectID:(NSString*)objectID withSuccessBlock:(void (^)())successBlock { void (^successWrapperBlock)(void) = ^{ //Some processing of returned data is done here if(successBlock) { successBlock(); } }; [HTTPClient fetchObjectDataWithObjectID:objectID withSuccessBlock:successWrapperBlock failureBlock:nil]; } @end
...我正在尝试找出检查最后一个程序successBlock
是否正在执行的最佳方法,以便我可以告诉委托人它已完成数据的获取。我在代码“ <---这项工作会吗?”中有评论。标记正在执行检查的语句,但对我来说并不安全,因为该块是异步的,并且if(objectID == [objectIDs lastObject])
在执行第一个successBock时可能为true。
如何确定何时执行最后一个successBlock
?在此先感谢您的智慧!
这里的指针比较(objectID == [objectIDs lastObject]
)比较好,因为如果不修改数组,您将获得相同的对象。如果您担心objectIDs
可能会被修改(例如,它实际上可能是一个可变数组,并在另一个线程上或通过诸如通知之类的副作用被修改),最好的保护就是在开始时复制该数组:
- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs { typeof(self) __weak blockSelf = self; NSArray *copiedIDs = [objectIDs copy]; for(NSString *objectID in copiedIDs) { [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{ if(objectID == [copiedIDs lastObject]) { [blockSelf.delegate finishedFetching]; } }]; } }
现在有两种方法可以调用该委托:
最后一次提取完成后,调用它。
或在最后一个对象的提取完成后调用它,即使正在进行其他提取请求。
这样你就可以:
使用类似@ChrisH建议的计数器。在最后一次提取完成后,无论处理顺序如何,都将调用委托。
使用指针比较。对lastObject的获取完成后,将调用委托。
为此,我认为您可以做一个小的优化。就其本身而言,它的缺点是它会捕获块中的数组,并在每次调用该块时调用不必要的方法调用。相反,您可以将最后一个对象保存在变量中,以便该块捕获最后一个对象而不是整个数组。请注意,通过块捕获数组不会造成任何伤害。它可能只是推迟释放一些内存。
因此,您可以这样做(@ChrisH的版本加上copy
):
- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs { typeof(self) __weak blockSelf = self; NSArray *copiedIDs = [objectIDs copy]; __block NSUInteger count = [copiedIDs count]; for(NSString *objectID in copiedIDs) { [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{ if(--count == 0) { [blockSelf.delegate finishedFetching]; } }]; } }
要么:
- (void)fetchObjectsFromServerWithObjectIDs:(NSArray*)objectIDs { typeof(self) __weak blockSelf = self; NSArray *copiedIDs = [objectIDs copy]; id lastObject = [copiedID lastObject]; for(NSString *objectID in copiedIDs) { [self fetchObjectDataForObjectID:objectID withSuccessBlock:^{ if(objectID == lastObject) { [blockSelf.delegate finishedFetching]; } }]; } }