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

私のテスト ケースには 4 つのインスタンスがあります。各インスタンスはセレクターを取得します。最初の 3 つは確実に開始されますが、「Got twitterstatus...」というログ行で示されるように、実際に完了するのは最後の 1 つだけです。

また、セレクターが呼び出すメソッドが「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

ここで見逃しているマルチスレッドの小さな基本的なナゲットは何ですか?

マルチスレッド化されていないコードを使用し、バックグラウンドで任意のメソッドを実行して乱数のスレッドをスピンオフすることは、失敗する運命にあります。

並行性は、最初から慎重に検討する必要がある設計パターンです (または、途方もないリファクタリング作業です)。

まず、ネットワーク接続ごとにスレッドを生成したくありません。第 2 に、これらは単なる HTTP 要求であるため、非同期 HTTP 通信用のクラスに組み込まれたシステムを使用する必要があります。最後に、同時実行モデルでは、データを中央ストアに同期するために使用しているメカニズムに到達するまで、すべてのデータを分離して保持する方法を正確に指定する必要があります。

詳細情報を確認せずに、そのコードがどこで軌道から外れているのかを判断するのは困難です。

于 2012-08-17T17:13:50.100 に答える