1

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

我正在使用 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];
                                             }
                                         }
                                     }];
}

在我的测试用例中有四个实例。每个实例都有它的选择器,你知道..selected。前三个肯定开始,但只有最后一个实际完成,如日志行所示,“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;
        }
    }
}];

}
4

2 回答 2

1

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

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

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

于 2012-08-17T18:11:53.047 回答
0

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

采用非多线程代码并通过在后台执行任意方法来分离随机数量的线程注定要失败。

并发是一种必须从一开始就仔细考虑的设计模式(或者是一项巨大的重构工作)。

首先,您不想为每个网络连接生成一个线程。其次,鉴于这些只是 HTTP 请求,您可能希望使用内置类的系统进行异步 HTTP 通信。最后,您的并发模型必须准确指定如何隔离所有数据,直到您使用任何机制将数据同步回中央存储。

很难在没有看到更多信息的情况下说该代码在哪里脱轨。

于 2012-08-17T17:13:50.100 回答