iphone - performSelector 在所有实例上进入方法,但只有一个线程完成

标签 iphone objective-c ios multithreading objective-c-blocks

这可能是一个幼稚的问题,但我还是会问这个问题,因为我找不到任何文档来解决我脑海中的这个问题。

我使用 Xcode45-DP4 在设备和模拟器中运行 iOS5.1。

我有一个循环遍历一个类的多个实例的数组。在该循环中,我在实例上使用 performSelector 来启动一个线程,该线程执行一些相对较慢的网络操作 — 拉取我宁愿在后台执行的数据。

    [arrayOfFriends enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        Friend *f = (Friend*)obj;
        iOSSLog(@"%d", idx);
        [f performSelectorInBackground:@selector(showDescription) withObject:nil];



-(void)fetchTwitterStatus
{
iOSSLog(@"Trying to fetch twitterstatus %@ %@", self.hash, self.twitterUserName);
[mLocalTwitterUser fetchTwitterAPIUserStatusWithScreenName:twitterUserName
                                     withCompletionHandler:^(NSArray *arrayOfStatus, NSError *error) {
                                         if(error) {
                                             iOSSLog(@"%@", error);
                                         } else {
                                             iOSSLog(@"Got twitterstatus %@ %d", self.twitterUserName, [arrayOfStatus count]);
                                             @synchronized(items) {
                                                 [items addObjectsFromArray:arrayOfStatus];
                                             }
                                         }
                                     }];
}

在我的测试用例中有四个实例。每个实例都有它的选择器,你知道……被选中。前三个肯定会开始,但只有最后一个真正完成,如日志行“Got twitterstatus...”所示,这很奇怪。

我还可以验证选择器调用“fetchTwitterStatus”的方法

我在这里缺少的多线程的基本小块是什么?

编辑:这里是 fetchTwitterAPIUserStatusWithScreenName...这里有很多,但实际上它是使用 JSON 响应调用 Twitter API 端点 user_timeline。

- (void)fetchTwitterUserStatusWithScreenName:(NSString *)screenname
                          excludeReplies:(BOOL)excludeReplies
                   withCompletionHandler:(OtterTwitterSearchHandler)completionHandler

{
self.twitterAPIStatusHandler = completionHandler;
//self.fetchTwitterUserStatusHandler = completionHandler;
NSString *urlString = [NSString stringWithFormat:@"https://api.twitter.com/1/statuses/user_timeline.json?screen_name=%@&include_rts=true&include_entities=true&exclude_replies=%@&count=50", screenname, excludeReplies?@"true":@"false"];
NSURL *url = [NSURL URLWithString:urlString];

#warning this isn't the way to do it - just checking the cache for refresh of the scroller
[[ASIDownloadCache sharedCache]removeCachedDataForURL:url];

iOSSRequest *request = [[iOSSRequest alloc] initWithURL:url
                                             parameters:nil
                                          requestMethod:iOSSRequestMethodGET];

NSMutableDictionary *oauthParams = [NSMutableDictionary dictionary];
[oauthParams setObject:[[Twitter sharedService] apiKey] forKey:kASIOAuthConsumerKey];
[oauthParams setObject:[[Twitter sharedService] apiSecret] forKey:kASIOAuthConsumerSecret];
[oauthParams setObject:[self oAuthAccessToken] forKey:kASIOAuthTokenKey];
[oauthParams setObject:kASIOAuthSignatureMethodHMAC_SHA1 forKey:kASIOAuthSignatureMethodKey];
[oauthParams setObject:@"1.0" forKey:kASIOAuthVersionKey];
[oauthParams setObject:[self oAuthAccessTokenSecret] forKey:kASIOAuthTokenSecretKey];

request.oauth_params = oauthParams;


[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
    if (error) {
        if (self.twitterAPIStatusHandler) {
            self.twitterAPIStatusHandler(nil, error);
            self.twitterAPIStatusHandler = nil;
        }
    } else {
        NSMutableArray *recentStatusForTwitterUser = [[NSMutableArray alloc]init];
        NSArray *array = [Twitter JSONFromData:responseData];
        [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            TwitterStatus *twitterStatus = nil;
            twitterStatus = [[TwitterStatus alloc]initWithDictionary:obj];
            [recentStatusForTwitterUser addObject:twitterStatus];
        }];
        if (self.twitterAPIStatusHandler) {
            self.twitterAPIStatusHandler(recentStatusForTwitterUser, nil);
            self.twitterAPIStatusHandler = nil;
        }
    }
}];

}

最佳答案

我建议尽可能使用已经提供的异步抽象。您需要直接处理线程的情况相当罕见/独特。

我发现将每个基于网络的后台任务视为队列上的同步 NSOperation 效果非常好。

获取 NSOperationQueue 的新实例,对其进行配置,向其添加任务,并管理队列。这种方法的好处是每个任务都可以作为一个简单的同步任务来实现,队列负责并发。您可以选择设置依赖项(此任务必须在该任务之前完成)。

关于iphone - performSelector 在所有实例上进入方法,但只有一个线程完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12009914/

相关文章:

iphone - 错误,Putpkt 写入失败

iOS App store 提交 - 我可以向苹果提交一个facebook测试用户帐户信息吗

c++ - 将 C++ 类与 Objective C 类混合

objective-c - 带有 EXC_BAD_ACCESS 的简单代码

ios - 为离线/断开连接保存花名册提议

javascript - iOS 自动化 JavaScript 是否支持 substring 功能?

iphone - iPhone 原生音频格式

iphone - 用于选择器 View iPhone 的 JSON 数组

ios - GKTurnBasedMatch 接收数据

javascript - 有没有办法使用 Apache Cordova 专门了解根可用空间(Android 和 iOS)?