I tried load an array from web service and display on tableview, But I have a problem.
I dont want display duplicate fields on tableview.
I want display only one field on table.
Now I have :
1234
1235
1234
6544
2234
6544
e.g 1234 and 6544 have duplicate
Load Array Code :
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
{
if ( [elementName isEqualToString:#"BranchID"] )
{
teveRetorno = YES;
}
else if ( [elementName isEqualToString:#"GetBranchResult"] )
{
myArray = [[NSMutableArray alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (teveRetorno)
{
[myArray addObject:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ( [elementName isEqualToString:#"BranchID"] )
{
[[self tableView]reloadData];
}
teveRetorno = NO;
}
Table Code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text =[myArray objectAtIndex:indexPath.row];
cell.textLabel.adjustsFontSizeToFitWidth = YES;
[cell setAccessoryType: UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
Remove the duplicates from the array you're using to populate the table. This can be done with:
NSOrderedSet *distinctItems = [NSOrderedSet orderedSetWithArray:self.myArray];
self.myArray = [distinctItems array];
Do this after you populate myArray from your data load and before you reload the table view.
This has not to do anything with tableView.
You might want to use something like this
if(![array containsObject:Value])
{
//add object to array.
}
if condition is true then only add value otherwise don't add it.
Deal with your datasource array.Remove the duplicate entries.Then Load data via reloadData
Related
I have xml file which I have to parse it. I'm following a youtube tutorials for it. I'm showing the parsed data from tags in a table view controller, But when i run the app no data is shown there, the table view controller is just empty. My code for parsing the file is this,
#import "QuestionParser.h"
#import "Question.h"
#interface QuestionParser()
#property NSXMLParser *parser;
#property NSString *element;
#property NSString *currentxref;
#property NSString *currenttext;
#property NSString *currentprompt;
#property NSString *currentexplanation;
#property NSString *currenttext1;
-(id)initWithArray:(NSMutableArray *)questionArray{
self = [super init];
if (self) {
self.questionArray = questionArray;
}
return self;
}
-(void)parseFile{
NSURL *url= [[NSBundle mainBundle]URLForResource:#"test" withExtension:#"xml"];
self.parser = [[NSXMLParser alloc]initWithContentsOfURL:url];
self.parser.delegate=self;
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
attributes:(NSDictionary<NSString *,NSString *> *)attributeDict{
self.element = elementName;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if ([self.element isEqualToString:#"xref"]) {
self.currentxref = string;
}
else if ([self.element isEqualToString:#"text"]){
self.currenttext = string;
}
else if ([self.element isEqualToString:#"prompt"]){
self.currentprompt = string;
}
else if ([self.element isEqualToString:#"explanation"]){
self.currentexplanation = string;
}
else if ([self.element isEqualToString:#"text"]){
self.currenttext1 = string;
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:#"question"]) {
Question *ques= [[Question alloc]initWithName:_currentxref text:_currenttext prompt:_currentprompt explanation:_currentexplanation text1:_currenttext1];
[self.questionArray addObject:ques];
}
self.element = nil;
}
This is how I'm loading data in datasource,
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.questionArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
Question *ques=self.questionArray[indexPath.row];
cell.textLabel.text=ques.xref;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#",ques.prompt];
return cell;
}
My xml file is this,
This method will execute after complete XML parsing. In this method reload the table view data.
-(void)parserDidEndDocument:(NSXMLParser *)parser{
// When the parsing has been finished then simply reload the table view.
[self.tableView reloadData];
}
If you want anything please follow this tutorial: https://www.appcoda.com/parse-xml-and-json-web-service/
I am trying to populate a UITableView in my viewcontroller (it is a delegate of UITableView)
The code below is something I've found online. I've made some changes so that I didn't need a UITableViewController in order to use it. However since I changed it, I am unable to figure out how to get the text to print in the cells. Before changing the code to allow my ViewcController subclass to be a delegate of UITableView. Could anyone point me in the right direction?
I have checked and the XML is parsing correctly. When the code reaches the if (marrXMLData.count != 0) in the startParsing method, marrXMLData is greater than 0 (8 being specific, the correct and total number of items in my XML)
code is from: http://www.theappguruz.com/blog/xmlparsing-with-nsxmlparser-tutorial
.m is below
DisplayTableViewController
#synthesize marrXMLData;
#synthesize mstrXMLString;
#synthesize mdictXMLPart;
- (void)viewDidLoad{
[super viewDidLoad];
[self startParsing];
}
- (void)startParsing{
NSData *fileData = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"file.xml"]];
NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithData:fileData];
[xmlparser setDelegate:self];
[xmlparser parse];
if (marrXMLData.count != 0) {
[self.myUITableView reloadData];
}
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;{
if([elementName isEqualToString:#"Content"])
marrXMLData = [[NSMutableArray alloc] init];
if([elementName isEqualToString:#"item"])
mdictXMLPart = [[NSMutableDictionary alloc] init];
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;{
if(!mstrXMLString)
mstrXMLString = [[NSMutableString alloc] initWithString:string];
else
[mstrXMLString appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;{
if([elementName isEqualToString:#"title"] || [elementName isEqualToString:#"url"]){
[mdictXMLPart setObject:mstrXMLString forKey:elementName];
}
if([elementName isEqualToString:#"item"])
[marrXMLData addObject:mdictXMLPart];
mstrXMLString = nil;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section{
return [marrXMLData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = [[[marrXMLData objectAtIndex:indexPath.row] valueForKey:#"title"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
cell.detailTextLabel.text = [[[marrXMLData objectAtIndex:indexPath.row] valueForKey:#"url"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return cell;
}
#end
EDIT:
After playing with it some more this method is not being called
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In the example code it is being called, but I'm not sure where. (Sorry, I am very new to iOS)
It sounds like your table view's delegate and/or dataSource links are not connected. If you set up the table view scene in IB (Interface Builder) then you just control-drag from the table view onto the view controller.
I tried load an array from web service and display on table view.This my tableview.But there is a mistake.Branchnames are
MEHMET FUDAYLÖZCAN,
SELAHATTİN KOÇAK,
Mehmet Süner Eken Petrol
Hasan Katkıcı Petrol
etc
etc
but table view show me like that
How I fix this ?
Th
Array Codes :
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes: (NSDictionary *)attributeDict
{
if ( [elementName isEqualToString:#"Branchname"] )
{
teveRetorno = YES;
}
else if ( [elementName isEqualToString:#"GetBranchNameResult"] )
{
myArray = [[NSMutableArray alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
if (teveRetorno) {
//[retornoSOAP appendString:string];
[myArray addObject:string];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ( [elementName isEqualToString:#"Branchname"] ) {
NSLog(#"My Array %#",myArray);
[[self tableView]reloadData];
//retornoSOAP = nil;
teveRetorno = NO;
}
}
Table Codes
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Return the number of rows in the section.
return [self.myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text =[myArray objectAtIndex:indexPath.row];
return cell;
}
There is nothing wrong with your table view or output. Your XMLParser is getting confused by certain characters (Ö) and calling didStartElement too early. Check out this - NSXMLParser divides strings containing foreign(unicode) characters
If your asking about the reason the text is getting cut off, set adjustsFontSizeToFitWidth for the textLabel of the cell. If that dosent fix it, then manually lower the font of the textLabel.
I'm a beginner in Xcode, and I have tried to create an app that downloads an XML file, parses it and adds every obtained element in an array. This array is then used by a Table View to create new rows. Unfortunately it didn't work. After NSLogging nearly every single step, I noticed that the app downloads and parses the files, but when it comes to adding the data to the array, the app empties the array and fills it again with the last element, as many times as there were elements in the beginning. Even like that, the Table View should have got some rows, but when I get out of the parsing routine, it seems that the array is filled with only "\n", which I don't understand. I do allocate and initialize the array properly:
myArray = [[NSMutableArray alloc]init];
And I add objects to the array with:
[myArray addObject:#"Hello"];
I precise that I use Xcode 4.6.2. for iOS 6, and that I am a beginner (please don't shoot me ;) )
Thanks for your help!
The XML File I use can be found on ilgl.lgl.lu/Missings_Data/Missings_Data.xml
Here parts of the code I use:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
if ([elementName isEqualToString:#"Released_classes"]) {
prof = [[NSMutableArray alloc]init];
classe = [[NSMutableArray alloc]init];
span = [[NSMutableArray alloc]init];
service = [[NSMutableArray alloc]init];
currentElement = [[NSMutableString alloc] init];
NSLog(#"Data containers initialized");
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
// ignore root and empty elements
if ([elementName isEqualToString:#"Missing_Class"] || [elementName isEqualToString:#"Released_classes"]) return;
if ([elementName isEqualToString:#"Classe"]) {
[classe addObject:currentElement];
NSLog(#"Added element to Classe: %#", currentElement);
NSLog(#"Elements in class: %#", classe);
return;
}
if ([elementName isEqualToString:#"Professeur"]) {
[prof addObject:currentElement];
NSLog(#"Added element to Prof: %#", currentElement);
NSLog(#"Elements in prof: %#", classe);
return;
}
if ([elementName isEqualToString:#"Lecon_libérée"]) {
[span addObject:currentElement];
NSLog(#"Added element to Span: %#", currentElement);
NSLog(#"Elements in span: %#", classe);
return;
}
if ([elementName isEqualToString:#"Service"]) {
[service addObject:currentElement];
NSLog(#"Added element to Service: %#", currentElement);
NSLog(#"Elements in service: %#", classe);
return;
}
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[currentElement setString:string];
}
#pragma mark - Table View Data Organization
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
NSLog(#"Number of sections: predefined 1");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSLog(#"Number of rows: %i", [classe count]);
return [classe count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
NSString *cellText = [classe objectAtIndex:indexPath.row];
cell.textLabel.text = cellText;
NSLog(#"Cell being created: %#", cellText);
return cell;
}
EDIT
Thanks to Wain, I added currentElement = nil before the end of every if condition in parser:didEndElement:and the verification he gave me. It now works perfectly! Thanks to all those who tried to help :)
You're reusing currentElement all the time and updating the value. Every time you update the value you overwrite the old value - everywhere you previously stored it (it's the same object in all the arrays).
At the end of parser:didEndElement: you want to set currentElement = nil;. Then, in parser:foundCharacters: you want a check:
if (currentElement == nil) {
currentElement = [[NSMutableString alloc] initWithString:string];
} else {
[currentElement appendString:string];
}
Im trying to parse XML (which seems ok) and populate a Table View on Iphone. I'm working from apples siesmec examples.
My XML looks something like this and has about 10 entries going from artist1 to artist10
<promo>
<id>
42
</id>
<artistname>
artist1
</artistname>
<img>
http://address.com/avatar_42.jpg
</img>
</promo>
If I put in breakpoints I can see all of the correct names but when the parsing is finished all 10 cells in my table say "artist10:
The Code for the xml is in the file as the table view controller. Can you see anything thats glaring a stupid mistake?
#pragma mark Parser constants
// Limit the number of parsed earthquakes to 50.
static const const NSUInteger kMaximumNumberOfEarthquakesToParse = 50;
static NSUInteger const kSizeOfEarthquakeBatch = 10;
// Reduce potential parsing errors by using string constants declared in a single place.
static NSString * const kArtistName = #"artistname";
static NSString * const kEntryElementName = #"promo";
static NSString *const kEntryElementID =#"id";
static NSString *const kEntryElementImg=#"img";
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if (parsedPromoListCounter >= kMaximumNumberOfEarthquakesToParse) {
// Use the flag
didAbortParsing = YES;
[parser abortParsing];
}
if ([elementName isEqualToString:kEntryElementName]) {
PromoListItem *promoitem = [[PromoListItem alloc] init];
self.currentPromoListObject = promoitem;
[promoitem release];
} else if ([elementName isEqualToString:kEntryElementImg]) {
//nothing for now
} else if ([elementName isEqualToString:kArtistName] || [elementName isEqualToString:kEntryElementImg] || [elementName isEqualToString:kEntryElementID]) {
accumulatingParsedCharacterData = YES;
// The mutable string needs to be reset to empty.
[currentParsedCharacterData setString:#""];
}
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if ([elementName isEqualToString:kEntryElementName]) {
[self.currentParseBatch addObject:self.currentPromoListObject];
parsedPromoListCounter++;
if (parsedPromoListCounter % kSizeOfEarthquakeBatch == 0) {
[self performSelectorOnMainThread:#selector(addPromosToList:) withObject:self.currentParseBatch waitUntilDone:NO];
self.currentParseBatch = [NSMutableArray array];
}
} else if ([elementName isEqualToString:kArtistName]) {
self.currentPromoListObject.artistName=self.currentParsedCharacterData;
} else if ([elementName isEqualToString: kEntryElementID]) {
self.currentPromoListObject.artistID = self.currentParsedCharacterData;
} else if ([elementName isEqualToString:kEntryElementImg]) {
self.currentPromoListObject.imgLink=self.currentParsedCharacterData;
}
// Stop accumulating parsed character data. We won't start again until specific elements begin.
accumulatingParsedCharacterData = NO;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (accumulatingParsedCharacterData) {
// If the current element is one whose content we care about, append 'string'
// to the property that holds the content of the current element.
[self.currentParsedCharacterData appendString:string];
}
}`
And this is how I populate my table view
#pragma mark Table View Methods
// The number of rows is equal to the number of earthquakes in the array.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.promoList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// Each subview in the cell will be identified by a unique tag.
static NSUInteger const kartistNameLabelTag = 2;
// Declare references to the subviews which will display the earthquake data.
UILabel *artistNameLabel = nil;
static NSString *kpromoCellID = #"promoCellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kpromoCellID];
if (cell == nil) {
// No reusable cell was available, so we create a new cell and configure its subviews.
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kpromoCellID] autorelease];
artistNameLabel = [[[UILabel alloc] initWithFrame:CGRectMake(10, 3, 190, 20)] autorelease];
artistNameLabel.tag = kartistNameLabelTag;
artistNameLabel.font = [UIFont boldSystemFontOfSize:14];
[cell.contentView addSubview: artistNameLabel];
} else {
// A reusable cell was available, so we just need to get a reference to the subviews using their tags.
artistNameLabel = (UILabel *)[cell.contentView viewWithTag:kartistNameLabelTag];
}
// Get the specific promo for this row.
PromoListItem *promo = [promoList objectAtIndex:indexPath.row];
// Set the relevant data for each subview in the cell.
artistNameLabel.text =promo.artistName;
return cell;
}
This was driving me mad so I went for a different approach.
Here is the code implementation I did
I'm not sure which approach is better. Maybe somebody would have an opinion on this?
The first version that I couldn't get working seemed to give you more control over what character data gets parsed. That's the only real benefit that I can see.
(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
if([elementName isEqualToString:#"promolist"]) {
//Initialize the array.
promoList = [[NSMutableArray alloc] init];
}
else if([elementName isEqualToString:kEntryElementName]) {
//Initialize the book.
//aBook = [[Book alloc] init];
//aBook =[[PromoListItem alloc] init];
PromoListItem *promo = [[PromoListItem alloc] init];
self.currentPromoListObject = promo;
[promo release];
}
NSLog(#"Processing Element: %#", elementName);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if(!currentParsedCharacterData)
currentParsedCharacterData = [[NSMutableString alloc] initWithString:string];
else
[currentParsedCharacterData appendString:string];
NSLog(#"Processing Value: %#", currentParsedCharacterData); }
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
if([elementName isEqualToString:#"promolist"])
{
[self.tableView reloadData];
return;
}
//There is nothing to do if we encounter the promo element here.
//If we encounter the promo element howevere, we want to add the book object to the array
// and release the object.
else if([elementName isEqualToString:kEntryElementName]) {
[promoList addObject:currentPromoListObject];
[currentPromoListObject release];
currentPromoListObject = nil;
}
else{
[currentPromoListObject setValue:currentParsedCharacterData forKey:elementName];
}
[currentParsedCharacterData release];
currentParsedCharacterData = nil;
}