Выделение памяти в отдельном NSThread для загрузки NSDictionary в фоновом режиме? - PullRequest
0 голосов
/ 24 апреля 2010

Я пытаюсь запустить фоновый поток для извлечения данных 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:@""];
}

1 Ответ

1 голос
/ 24 апреля 2010

Самое простое, что можно сделать, это создать словарь в отдельном потоке, а затем установить его как свойство в основном потоке, например:

- (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 - это ивар, к которому у вас есть прямой доступ. Это плохая идея, так как NSXMLParser не является поточно-ориентированным - я бы рекомендовал вместо этого реализовать его как локальную переменную. Если вам это нужно в качестве ивара, используйте атомарное свойство и блокировки и получите к нему доступ только через средства доступа.

...