What is this approach of iPhone Programming called? - iphone

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.

Related

Core data refactoring

Hi
Normally all the methods like
'- (NSFetchedResultsController *)fetchedResultsController '
are placed in the code of view controllers. I find it a bit messy to write Data Fetching code along with lifecycle methods or table delegate methods.
So my point is should I refactor the CoreData methods to some other helper class say DataLoader and then call them in view controllers?
Is this a wrong thing to do or am I going to loose some coding benefits of Core Data methods.
I would say moving the fetchedResultsController to a helper class is a good idea.
A problem I encounter often is to get the spelling of attributes right.
For example I do a predicate and want to filter on an attribute called #"isSelected". There is no check by the compiler nor by the linker to check the string isSelected. I will have to double check each line where the string has been used.
A search&replace won't work on the misspellings because I don't know what bugs have been introduced.
When I get the predicate wrong then no results will be fetched. Problem is that I don't know if there are no matching rows or if I have filtered wrong. I will need to check at runtime and that consumes time.
For predicates the saved templates exist, so predicates are not a perfect example. But think about value forKey: and we are at square one.
Now if all the fetchedResultsController are in one file then checking would become easier. At least it reduces the possibility of missing that little misspelling in a far away and rarely used class.
...or am I going to loose some coding benefits of Core Data methods.
I tend to say no, but other please feel free to jump in.
#Mann yes of course you can do that without loosing any coding benefits.....if u don't want to write Data Fetching code in you view Controller do not write there.....Make any other class lets say it DataLoader and write the fetching code in method of this class......and call this method by making the object of DataLoader class ....u will be able to fetch data from database
Hope u get it!

What is a good pattern for interpreting Core Data validation messages and displaying them on the iPhone?

I've implemented a small proof-of-concept app using Core Data to accept some object attribute values from the user via text fields and it's all working great thanks to information found here and in the iPhone Core Data Recipes app. But I'm at the point where I need to display object validation errors to the user and I can't find a recommended way of handling this. The code in the Recipe app just logs the error and says to "Replace this implementation with code to handle the error appropriately." Great, thanks.
I'm sure there are a multitude of ways to interpret, parse and transmit the validation error information to the user but what I'd like to know is if there are some best practices or a pattern that someone has implemented that I could follow. Where should the validation code like [newObject valdiateForInsert&error]; be placed? In NSManagedObject subclasses? In the UIViewController that handles the screen the enables the object to be added? Maybe in an app-wide ValidationController?
All the validation errors are returned in the NSError's userInfo, which is a NSDictionary of various NSValidation keys and values. Is there a good way of translating this error info into something that would be helpful to the user? For example, I have a rule in my Core Data model that a certain attribute can only be 3 characters long. If in the process of saving or updating an object I get a validation error, I need to parse out the NSError userInfo and find values for the NSValidationErrorKey (the name of the attribute), the NSValidationErrorValue (the value on the object that caused the error) and the NSValidationErrorPredicate (the rule that was violated, which in this case returns length <= 3.
Is there a good, generally accepted way of gathering and munging this data into something that can be passed back to the user? I'm currently pulling the NSError info into strings and then falling through a series of conditional statements for each attribute that I'm validating, and it's so ugly that I kinda want to puke when I look at it. There has to be a better, cleaner way to consume Core Data validation errors and pass a readable version to the user.
Validations are not there for the user. They are there so the code can maintain the integrity of the object graph. Validation methods are not called by the managed object context until the time at which context is saved. That time might be very distant from the time of input.
However, you can call an objects validation methods directly before you set an attribute. The validation methods have the form:
- (BOOL)validateTimeStamp:(id *)valueRef error:(NSError **)outError;
Suppose you have an attribute name for a managed object subclass PeopleMO. The validation method to check for an empty string might look like:
- (BOOL)validateName:(id *)valueRef error:(NSError **)outError{
BOOL isValid=NO;
NSString *toTest=(NSString *) valueRef;
if (![toTest isEqualToString:#""]) {
isValid=YES;
}
return isValid;
}
You could call it anywhere like:
NSString *newName=// some UI element text
PersonMO *newPerson=//.. insert new PersonMO object
if ([newPerson validateName:newName error:nil]) {
newPerson.name=newName;
}else{
//... inform user name is invalid
// ... possibly delete newPerson object from context
}
This is most useful where you have situations in which the validity of the value of one attribute depends on one or more other attributes of the same object.

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?)

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

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

Incompatible pointer type: How can I use a CFType derived object within NSObject derived collection objects?

I'm trying to use ABRecordRef within an NSMutableArray, but it doesn't seem to work. I know that ABRecord is a C class, but I thought that ABRecordRef was the work around Objective-C class that allowed me to use it with NSObjects. What do I need to do to make this work?
What do you mean by "Not Working"? As in, you get compile or run-time errors?
As I noted in the response to the other poster, you can't use the Objective-C API on the iPhone (There also is no true ABrecord class to brdge to).
Generally it's a really good idea with the address book stuff on the iPhone to copy out elements you are interested in, and save the copied values off in something like a dictionary. If you need to save all the elements, you have to have code that reads every value as defined in the AddressBook.h header file, there's no API way to generically walk the records.
Also remember that at any time, the user might change the address book if they quit your app and come back - so be careful about what you change after they relaunch the app if you are storing values!!