2013-09-28 3 views
0

Я создал NSMutableArray под названием tempArray, который содержит символы для трех элементов, которые я хочу. В настоящее время, когда я устанавливаю точку останова и запускаю синтаксический анализатор, tempArray правильно изменяется каждый раз и дает мне необходимую мне информацию (широта, долгота, имя-имя).Все объекты, переписанные addObject: при использовании NSXMLParser

Затем, когда анализатор вызывает метод didEndElement... для «а-места», я добавляю tempArray к главному NSMutableArray имени parsedNearMe, который должен содержать все а-места (каждое имеет имя, широта, долгота) ,

Это все работает так, как ожидалось.

Проблема: Каждый раз, когда я добавить tempArray к parsedNearMe, это добавляет новый объект, но устанавливает все существующие объекты к ценностям нового объекта.

То, что я думаю, что это проблема Я думаю, что проблема заключается в том, что, так как я устанавливаю текущие элементы для tempArray, и каждый раз, когда я перезапись каждого объекта в parsedNearMe, потому что каждый объект является указателем на то же самое tempArray.

Возможные решения я покушений или исследуемые не повезло -Somehow очистить указатель, так что я могу повторно использовать tempArray (или реинициализировать?) -dynamically создать новое имя вместо tempArray каждый раз (Дон» t думаю, возможно в Objective-C)

Я ценю любые предложения, так как я потратил столько часов на это, уже занимаюсь кругами. Кроме того, я бы хотел, чтобы текущая архитектура работала (получая один большой массив массивов, поэтому я могу вызвать 1 из массивов и получить все данные, которые мне нужны для этой аннотации).

Мой код выглядит следующим образом:

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
{ 

    if ([elementName isEqualToString:@"a-location"]) 
    { 
     if (!tempArray) 
      tempArray = [[NSMutableArray alloc] init]; 
     return; 
    } 


    if ([elementName isEqualToString:@"latitude"]) 
    { 
     latitude = [[NSMutableString alloc] init]; 
     return; 
    } 


    if ([elementName isEqualToString:@"longitude"]) { 
     longitude = [[NSMutableString alloc] init]; 
     return; 
    } 


    if ([elementName isEqualToString:@"the-name"]) { 
     myName = [[NSMutableString alloc] init]; 
     return; 
    } 

} 



-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
    currentString = [[NSMutableString alloc]init]; 
    [currentString appendString:string]; 

} 



- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{ 

    if ([elementName isEqualToString:@"latitude"]) { 
     [tempArray addObject:currentString]; 
     return; 
    } 

    if ([elementName isEqualToString:@"longitude"]) { 
     [tempArray addObject:currentString]; 
     return; 
    } 

    if ([elementName isEqualToString:@"the-name"]) { 
     [tempArray addObject:currentString]; 
     return; 
    } 

    if ([elementName isEqualToString:@"a-location"]) 
    { 
     [parsedNearMe setObject:tempArray forKey:[NSDate date]]; 
     [tempArray removeAllObjects]; 
    } 
} 

ответ

1

Есть несколько проблем:

  1. didEndElement для a-location устанавливает значение заклиненную по дате, но затем принимает указатель, который указывает к тому же объекту и удаляет все элементы, которые были в этом объекте. Таким образом, вместо того, чтобы:

    if ([elementName isEqualToString:@"a-location"]) 
    { 
        [parsedNearMe setObject:tempArray forKey:[NSDate date]]; 
        [tempArray removeAllObjects]; 
    } 
    

    Вы можете заменить это:

    if ([elementName isEqualToString:@"a-location"]) 
    { 
        [parsedNearMe setObject:tempArray forKey:[NSDate date]]; 
        tempArray = nil; // make sure you don't touch that object you just added to parsedNearMe 
    } 
    
  2. Я сомневаюсь, что этот конкретный XML будет страдать от этой проблемы, но ваш foundCharacters предполагает, что один вызов будет возвращать все данные. Это неверное предположение. Иногда требуется несколько вызовов.

  3. У вас также есть foundCharacters добавить строки для частей XML, для которых у вас нет интереса. Вы должны убедиться, что currentString равен nil, за исключением случаев синтаксического анализа широты, долготы и имени.

Так, по крайней мере, я хотел бы предложить что-то вроде следующего:

- (void)parserDidStartDocument:(NSXMLParser *)parser 
{ 
    parsedNearMe = [[NSMutableDictionary alloc] init]; 
    currentString = nil; 
} 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
{ 
    if ([elementName isEqualToString:@"a-location"]) 
    { 
     tempArray = [[NSMutableArray alloc] init]; 
    } 
    else if ([elementName isEqualToString:@"latitude"] || 
      [elementName isEqualToString:@"longitude"] || 
      [elementName isEqualToString:@"the-name"]) 
    { 
     currentString = [[NSMutableString alloc] init]; 
    } 
} 

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
    [currentString appendString:string]; 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{ 
    if ([elementName isEqualToString:@"latitude"] || 
     [elementName isEqualToString:@"longitude"] || 
     [elementName isEqualToString:@"the-name"]) 
    { 
     [tempArray addObject:currentString]; 
     currentString = nil; 
    } 
    else if ([elementName isEqualToString:@"a-location"]) 
    { 
     [parsedNearMe setObject:tempArray forKey:[NSDate date]]; 
     tempArray = nil; 
    } 
} 

Это отражает текущую логику, создавая словарь шпонкой некоторой случайной временной метки и значение для каждого словаря item - массив широты, долготы и имени.

Лично я думаю, что эта конструкция страдает от двух дополнительных недостатков, хотя:

  1. Вы манипуляции своего словаря некоторых случайного объекта, [NSDate date]. Это не имеет значения. Вы могли бы также сделать этот массив.

  2. Ваш массив широт, долготы и имени неоднозначен. Ваша структура данных сильно зависит от порядка элементов в файле XML. Если вы собираетесь использовать словарь для чего-нибудь, я бы использовал его здесь.

Итак, нижняя строка, а не словарь, значения которого являются массивами, я бы перевернул это. Я бы предложил массив объектов словаря. Я думаю, что parsedNearMe должен быть NSMutableArray. И вместо NSMutableArray называется tempArray, вы должны использовать NSMutableDictionary называется tempDictionary:

Во-первых, определяют несколько Ивар:

NSMutableArray *parsedNearMe;   // this was a NSMutableDictionary 
NSMutableDictionary *tempDictionary; 

И тогда ваши NSXMLParserDelegate процедуры может выглядеть так:

- (void)parserDidStartDocument:(NSXMLParser *)parser 
{ 
    parsedNearMe = [[NSMutableArray alloc] init]; 
    currentString = nil; 
} 

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict 
{ 
    if ([elementName isEqualToString:@"a-location"]) 
    { 
     tempDictionary = [[NSMutableDictionary alloc] init]; 
    } 
    else if ([elementName isEqualToString:@"latitude"] || 
      [elementName isEqualToString:@"longitude"] || 
      [elementName isEqualToString:@"the-name"]) 
    { 
     currentString = [[NSMutableString alloc] init]; 
    } 
} 

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
    [currentString appendString:string]; 
} 

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{ 
    if ([elementName isEqualToString:@"latitude"] || 
     [elementName isEqualToString:@"longitude"] || 
     [elementName isEqualToString:@"the-name"]) 
    { 
     [tempDictionary setObject:currentString forKey:elementName]; 
     currentString = nil; 
    } 
    else if ([elementName isEqualToString:@"a-location"]) 
    { 
     [parsedNearMe addObject:tempDictionary]; 
     tempDictionary = nil; 
    } 
} 

Или, если вы хотите сохранить широту и долготу как объекты NSNumber вместо этого в качестве строк, вы можете заменить didEndElement на:

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{ 
    if ([elementName isEqualToString:@"latitude"] || 
     [elementName isEqualToString:@"longitude"]) 
    { 
     [tempDictionary setObject:@([currentString doubleValue]) forKey:elementName]; 
     currentString = nil; 
    } 
    else if ([elementName isEqualToString:@"the-name"]) 
    { 
     [tempDictionary setObject:currentString forKey:elementName]; 
     currentString = nil; 
    } 
    else if ([elementName isEqualToString:@"a-location"]) 
    { 
     [parsedNearMe addObject:tempDictionary]; 
     tempDictionary = nil; 
    } 
} 
+0

Очень хорошо структурированный ответ, спасибо. Хотя я еще не пробовал ваше решение, я считаю, что это решит мою проблему: tempArray = nil; Я также согласен с вашими конструкторскими предложениями. На самом деле, я изначально имел его как только два NSMutableArrays, но в итоге появился с использованием современного дизайна словарей, потому что я просто пытался много способов и думал, что, возможно, использование NSDictionary с ключом позволит решить проблему перезаписи объектов каждый раз. – Joel

+0

Кроме того, именно поэтому я пытался поставить случайную дату в качестве ключа. По какой-то причине я думал, что дать ему уникальное имя (дата) остановит объекты от перезаписи. Я также попытался запустить счетчик в 0 и использовать номер в качестве ключа. Спасибо, что расчистил это :). – Joel

Смежные вопросы