Parsing multiple XML files into one or more Object-classes? - iphone

My app is made up of a TabBarController, each tab with a UITableView.
On launch I parse an XML file from my server into an Object class and then display the objects in the first tableview.
My question is, what do I do when I want to parse a second XML file? Currently, when doing so, the information in "XML-file-2" will overwrite the objects parsed by "XML-file-1". How do I go about this properly? Do I set up another Object class for each XML file or is there another to work around the issue?
I am using NSXMLParser.

I think you should consider having two instances of XMLParser, one for each XML file you want to read. It allows you to read as many XML files concurrently without affecting each other. It is also more modular.

on line 21 of that snippet ( http://pastie.org/537227 ) you are setting the products array (appDelegate.products)to a new mutable array. if you want the second run to append to appDelegate.products, you should see if appDelegate.products already has objects in it, if so, don't assign a new array to it, just add to them to it using NSMutableArray's addObject: method

... Don't overwrite the data that's already there...?
If you're displaying the contents in a UITableView, then I'd be willing to bet you've got an NSArray in there somewhere. Hopefully, if you've set this up properly, the NSArray contains model objects, each one of which corresponds to one row in your UITableView. However, I would suggest using NSMutableArray. Then when you parse the second XML file and build your model objects out of that, just use NSMutableArray's addObject: method and then reloadData on the UITableView.

As notnoop already mentioned, to make multiple NSXMLParser instances would be the best solution.
A open source iPhone RSS reader called Simple RSS Reader would be a good sample of what you want now.
You might use RSSParser class of the Simple RSS Reader as it is.
HTH

Related

Adding new cells 'above' existing ones (rather than 'below') in UITableView

Am a newbie to iOS programming. This is what am trying to do:
The user enters some text in the screen and it keeps getting added to a UITableView.
As usual, it's getting added from the top.
But I want to add it from the bottom i.e. each new message that's added is added above the rest/existing ones, and not below.
Can someone offer some pointer on this please!
Thanks
Priya
NSMutableArray's -addObject method appends the object to the end of the array. If you want to put it at the beginning, just use this method instead:
[inputArray insertObject:userInput atIndex:0];
There are other ways to put objects in the array and move them around. Take a look at the documentation:
NSMutableArray Documentation
Are you using CoreData? If so, maybe you can set a creation time and sort it descending?
If you don't use CoreData but store the data in some sort of array, just add new objects to the beginning of the array and then reload the data.
[array insertObject:data atIndex:0];

What is this approach of iPhone Programming called?

I have a sample code wherein:
I am unable to understand how data flows from database to reports because there is no place to set or fetch data explicitly. It is all done through custom objects.
Even we are not able to fetch data through console using NSLog as it has ENUM keys
All objects are custom objects so if we put it in NSLogs we get structure like < CustomObject-hexcode>. Many of the classes again comprise of objects from other classes.
Even if I try to debug code by putting breakpoint, then after few steps it show Hexadecimal codes
I wont be able to put sample code as it is a whole project containing lot of files.
Can you please let me know what kind of approach has been used? It looks like some sort of encapsulation.
Thanks!
Write categories that implement the - (NSString* ) description method for each custom object that displays all variables the custom obejects hold, you can there translate each of the enum values to strings. Then you can use NSLog to output objects and get readable results.
you need to debug application. and for this "All objects are custom objects so if we put it in NSLogs we get structure like < CustomObject-hexcode>"
you need to integrate a category class in your project. Search on google for override description of nsobject. You will get nslog in proper format.
It sounds like some kind of custom ORM with serialization / deserialization etc. Euuuwww.

iphone textview showing data coming from coredata

I need to show some data in a textview coming from coredata (like this for example),
I imagine a possible solution (dont know if is the right one or how to do it, please advice),
so bring the data from coredata to a string, appending all the data neeeded in the string with the equivalent of "\n" for new line where needed; then show the data in the text view,
(please refer to example image to know what is needed)
so how to bring the data from coredata to this textView with this formatting?
please note I only want to know if this is a proper way to do it (imagined solution? or if there is a more proper way?)
Thanks a lot!!
I tackled an identical issue in one of my apps.
The approach I took was to first structure my core data model so that the pieces of data had enough granularity so that I could construct different views as required. In other words, instead of one property for "name", I have three properties. One for "first name", one for "middle name", and a third for "last name". I also created a separate "data layer" object so that I could easily get to pieces of my data from anywhere in the app.
Next, to construct my view that shows data in a sort of form view. Using Interface Builder, I simply laid out a view using primarily UILabel view objects as placeholders. Then, as the user switches between person views, I call on the data layer object for pieces of data and just "fill in" in the UILabel placeholders.
I also render a PDF file in paragraph form. Similar to what you are doing. For that, I use an NSMutableString along with the NSString stringWithFormat convenience method. Using NSMutableString, you can concatenate strings with newline characters embedded as needed. For this, I also call on my data layer object for the pieces of data.
[[NSString stringWithFormat:#"Date of Visit: %#", dateOfVisitString] drawInRect:stringRect withFont:theFont];
Hope this helps. Good Luck.
Yes, your strategy of
'bring the data from coredata to a
string, appending all the data neeeded
in the string with the equivalent of
"\n" for new line where needed; then
show the data in the text view'
will work fine.
(Bit of an odd answer, but it seems to be what you're asking, from your comment clarification.)
Your approach is fine. If you're targeting a textview for display, then constructing a formatted string from a managed object's properties is reasonable. Use NSMutableString and its -appendFormat: method.
You may also want to explore creating a report form out of UILabels laid out inside a UIView. Interface Builder would be the tool to use for this, but you could also create this in code.

iOS XML writer class

I want to create a game, that will use a level system. So i want to store my levels and to be able to change them during the game (to save the state). So i decided to use XML for storing levels. I found NSXmlParser class for reading from XML, but i can't find a writer to save the level state. In my game the level state and the level are very similar ( i have a lot of movable objects), so i don't wan't to store the level state data separated from the level it belongs. The problem is that i can't find a way to easily modify XML files on iPhone. Maybe i'm using a bad approach.
If you throw the data in an NSDictionary, you could do (with caveats):
[myDictionary writeToFile:pathToPlist atomically:YES];
Try the open source XML stream writer for iOS:
Written in Objective-C, a single .h. and .m file
One #protocol for namespace support and one for without
Example:
// allocate serializer
XMLWriter* xmlWriter = [[XMLWriter alloc]init];
// start writing XML elements
[xmlWriter writeStartElement:#"Root"];
[xmlWriter writeCharacters:#"Text content for root element"];
[xmlWriter writeEndElement];
// get the resulting XML string
NSString* xml = [xmlWriter toString];
This produces the following XML string:
<Root>Text content for root element</Root>
I would recommend using KissXML. The author started in a similar situation as you and created an NSXML compatible API wrapper around libxml. He discusses the options and decisions here on his blog.
You can use the C libary libxml2 to read and write XML. Here's a quick intro: Cocoa Samurai: Getting Some XML Love with libXML2.
However, have you considered using CoreData or implementing the NSCoding protocol? NSCoding would be easier to add to existing classes.

Objective C Object Functioning & Passing Arrays

I apologise if this has been asked before but I can't find the info I need.
Basically I want a UITableView to be populated using info from a server, similar to the SeismicXML example. I have the parser as a separate object, is it correct to alloc, init an instance of that parser & then tell RootViewController to make it's table data source a copy of the parser's array.
I can't include code because I haven't written anything yet, I'm just trying to get the design right before I start. Perhaps something like:
xmlParser = [[XMLParser alloc] init];
[xmlParser getXMLData];
// Assuming xmlParser stores results in an array called returnedArray
self.tableDataSource = xmlParser.returnedArray
Is this the best way of doing it?
No, you don't want to do this. You don't want your view controller directly accessing the array of the data-model. This would work in the technical sense but it would be fragile and likely to fail as the project scaled.
As the projects grow in complexity, you will want to increasingly wrap your data model object (in this case the xmlParser) in protective layers of methods to control and verify how the data model changes. Eventually, you will have projects with multiple views, multiple view controllers as well as information entering from both the user and URLs. You need to get into the habit of using the data-model object not just a dumb store you dump stuff into but as an active manager and verifier of your data.
In a situation like this I would have my data-model's array completely wrapped by making it a #protected or #private property. Then I would have dedicated methods for fetching or inserting data into the actual array inside the data-model class itself. No objects outside of the data-model should actually have direct access to the array or have knowledge of its indexes.
So, in this case your data-model would have something like:
- (NSString *) textForLineAtIndexPath:(NSIndexPath *) anIndexPath{
//... do bounds checking for the index
NSString *returnString=[self.privateArray objectAtIndex:anIndexPath.row];
if (returnString=='sometest'){
return returnString;
}
return #""; //return an empty string so the reciever won't nil out and crash
}
as well as a setTextForLineAtPath: method for setting the line if you need that.
The general instructional materials do not spend enough (usually none) time talking about the data-model but the data-model is actually the core of the program. It is where the actual logic of the application resides and therefore it should be one of the most complex and thoroughly tested class in your project.
A good data-model should be interface agnostic i.e. it should work with a view based interface, a web based interface or even the command line. It should neither know nor care that its data will be displayed in a tableview or any other interface element or type.
When I start a new project, the first thing I do is comment out the '[window makeKeyAndVisible];' in the app delegate. Then I create my data-model class and test it old-school by loading data and logging the outputs. Only when it works exactly how I wish it to do I then proceed to the user interface.
So, think real hard about what you want the app to do on an abstract level. Encode that logic in a custom class. Isolate the data from all direct manipulation from any other object. Verify all inputs to the data before committing.
It sounds like a lot of work and it is. It feels like overkill for a small project and in many cases it is. However, getting the habit early will pay big dividends very quickly as your apps grow in complexity.
Not quite. You want the data source to be an object that implements the UITableViewDataSource protocol; what I would do in this situation is create an object that implements that protocol and parses XML, so that you can alloc-init it, then set the data source to that object and have it update the table view as appropriate. So based off your code (and assuming you're running within the table view's controller):
XMLParserAndDataSource xpads = [[XMLParserAndDataSource alloc] init];
[xpads getXMLData];
self.tableView.dataSource = xpads;
It's probably a good idea to give this class itself a reference to an NSXMLParser object, so you can use that to parse the XML, then provide convenience methods (like getXMLData) as well as the UITableViewDataSource methods for your own use. (If you go this route, you should also make your XMLParserAndDataSource class implement the more useful of the NSXMLParser delegate methods, and use them as appropriate to update your table view.)
I'm a Mac programmer and not an iPhone programmer; but on the mac,
self.tableDataSource = xmlParser.returnedArray is not correct. You are supposed to either bind the table's content to an Array Controller (if iPhone has one?) or set the datasource outlet to your RootViewController.
In your rootview controller, you would implement the methods:
– tableView:cellForRowAtIndexPath:
– tableView:numberOfRowsInSection:
For – tableView:cellForRowAtIndexPath: you would return a UITableViewCell with the data you received from the XML parsing according to the index path like so:
UITableCell *myCell = [UITableCell new];
myCell.textLabel.text = [parsedXMLArray objectAtIndex:[indexPath indexAtPosition:indexPath.length-1]];
return myCell;
(Something people don't know is that you can use the + new class method on all NSObject subclasses which automatically call alloc/init.)
For – tableView:numberOfRowsInSection just return the count of the data array:
return parsedXMLArray.count;
Can't edit my question nor post replies, can only post my response as answer.
#TechZen: I'm somebody who tries to form analogies, helps me understand. What you're saying is something like: My original idea was like going into the file room & dumping all the originals on my desk to work on where as you suggest the object be more like an organised file clerk who will search through the data for me and only return the specific datum that I need while being the only one with direct access to that data.
Have I understood correctly?
#Tim: What if I later need the parser to get data for something which is not a table? That's why I thought to dump it into an array & let the caller decide what to do with the data. Would you suggest a second object that would supply the data in the newly required form? (Am I sort of one the right track here or way off?)