0

バックグラウンド スレッドを起動して、Web サービスから XML データを取得しようとしています。スレッドなしで同期的に開発したので、その部分が機能することはわかっています。これで、スレッドを生成して応答と解析を待機することにより、ノンブロッキング サービスを利用する準備が整いました。

スレッド内に NSAutoreleasePool を作成し、解析の最後に解放しました。スポーンするコードとスレッドは次のとおりです。

メインループ コードからスポーンします

 .
 .
 [NSThread detachNewThreadSelector:@selector(spawnRequestThread:) 
                          toTarget:self withObject:url];
 .
 .

スレッド (「自己」内) :

-(void) spawnRequestThread: (NSURL*) url  {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

 parser = [[NSXMLParser alloc] initWithContentsOfURL:url];

 [self parseContentsOfResponse];

 [parser release];
 [pool release];
}

このメソッドparseContentsOfResponseは、NSMutableDictionary に解析されたドキュメント コンテンツを入力します。データを頻繁に移動することを避け、コピーを作成するのではなく、スレッドを生成したメインループにデータを割り当て直したいと考えています。まず、それは可能ですか?そうでない場合は、メインスレッドから割り当てられたポインターを渡し、「dictionaryWithDictionary」メソッドで割り当てることができますか? それはとても非効率的なようです。

parseContentsOfResponse

-(void)parseContentsOfResponse {

    [parser setDelegate:self];
    [parser setShouldProcessNamespaces:YES];
    [parser setShouldReportNamespacePrefixes:YES];

    [parser parse];

    NSError *parseError = [parser parserError];
    if (parseError) {
        NSLog(@"%@", parseError);
        NSLog(@"publicID: %@", [parser publicID]);
        NSLog(@"systemID: %@", [parser systemID]);
        NSLog(@"line:%d column:%d", [parser lineNumber], [parser columnNumber]);
    }

    ready = YES;
}

最初の解析セクション

各セクションは、その elementStart が通知されると、要素文字列を作成します。elementEnd は、オブジェクトを辞書に追加し、要素を解放します。残りの詳細は冗長です。注意すべき点は、割り当てが NSZone に向けられていないため、スレッドのメモリ プールに存在する必要があることです。

- (void)parserDidStartDocument:(NSXMLParser *)parser {
    NSLog(@"%s", __FUNCTION__);
    currentChars    = [NSMutableString stringWithString:@""];
    elementQuestion = [NSMutableString stringWithString:@""];
    elementAnswer   = [NSMutableString stringWithString:@""];
    elementKeyword  = [NSMutableString stringWithString:@""];
}
4

1 に答える 1

1

最も簡単な方法は、次のように、別のスレッドで辞書を作成し、それをメイン スレッドのプロパティとして設定することです。

- (void)spawnRequestThread: (NSURL*) url  {
    NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
    //do stuff with dict
    [self performSelectorOnMainThread:@selector(doneWithThread:) withObject:dict waitUntilDone:NO];
}

- (void)doneWithThread:(NSDictionary *)theDict {
    self.dict = theDict; //retaining property, can be an NSDictionary
}

時間の経過とともに辞書の内容を変更する必要がありますか? その場合、メインスレッドで割り当てて他のスレッドで内容を変更することは可能ですが、スレッドセーフの問題について心配する必要がNSMutableDictionaryあります-スレッドセーフではないため、アトミックプロパティとロックを使用する必要があります:

//.h
@property (retain) NSMutableDictionary *dict; //don't use "nonatomic" keyword
@property (retain) NSLock *dictLock;

//.m
- (id) init {
    //blah blah
    dict = [[NSMutableDictionary alloc] init];
    dictLock = [[NSLock alloc] init];
    return self;
}

- (void)spawnRequestThread: (NSURL*) url  {
    //whenever you have to update the dictionary
    [self.dictLock lock];
    [self.dict setValue:foo forKey:bar];
    [self.dictLock unlock];
}

いずれにせよ、ロックは非常に高価で非効率的であるため、私は最初の方法を好む傾向があります (どちらがより高価かは正確にはわかりませんが、最初の方法はより単純で、スレッドセーフの問題を回避します)。

また、コードを見ると、あなたNSXMLParserが直接アクセスする ivar のようです。NSXMLParser スレッドセーフではないため、これは悪い考えです。代わりに、ローカル変数として実装することをお勧めします。ivar として必要な場合は、アトミック プロパティとロックを使用し、アクセサーを介してのみアクセスします。

于 2010-04-24T05:35:36.300 に答える