UITableView and NXXMLParser ... Calling Hierarchy - iphone

I am stuck in a strange situation , i am getting data from the website using XML files and i am filling an Array (NSMutableArray Type) that i later use to display the data on Table View. The problem is that functions related to UITableView are called earlier and at that time the Array is not filled, this cause the program to crash. When this function is executed arrayData is empty and count functions returns nothing. Is there any way that i call NSXMLParser functions earlier than the UITableView functions.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayData count];
}
Thanks,
Taimur

The array would return 0 if it existed but without containing any objects - so the app shouldn't crash. This means your array has not been initialized yet. You have propably added a pointer to your array as an instance variable and maybe as property, but you still need to create the actual object towards which that pointer should point.
So, if we're dealing with a property of a viewcontroller subclass here, add something like this to your viewDidLoad method:
NSMutableArray *newArray = [[NSMutableArray alloc] init];
self.arrayData = newArray;
[newArray release];

Your situation is not strange at all - it is extremely common when developing apps with asynchronous data loading requirements.
NSXMLParser is a SAX (event-driven) parser - it will parse data when the data is available. It is up to you when you choose to display your table, but obviously if you try to display it before the XML data is available then you will have to take steps to prevent a crash, or at the very least a bad user experience. Typically you would display an activity spinner or a "loading data..." message until the data is ready, and in a background thread load the XML. Once loaded, the BG thread should signal to the UI thread that the data is ready, and perhaps invoke reloadData on the table to load the data.

Related

Loop Until Array Has Data

I need to setup some sort of loop that runs until an array has data in it. A little bit of background information: the application talks to the server and gets some information and populates that information into an array. Only when that information is populated into the array can the view get changed to the next view (because the view is populated with information from the array).
How would I create this loop? I'm currently using an NSTimer but that is not suitable for my needs.
Thanks in advance!
When you say looping until I assume you really mean wait until.
First of if this waiting is to be done on the main thread just forget about it, never block the main thread.
Instead of a loop you probably want to use a lock, and wait for the condition. This requires a shared lock between the code where you wait for the array to populate, and the code where you populate the array.
First create a shared condition lock like this:
typedef enum {
MYConditionStateNoObjects,
MYConditionStateHaveObjects
} MYConditionState;
...
sharedArray = [[NSMutableArray alloc] init];
sharedLock = [[NSConditionLock alloc] initWithCondition:MYConditionStateNoObjects];
Your method that populates the array should then do:
[sharedLock lockWhenCondition:MYConditionStateNoObjects];
// Your stuff to get the objects to add here.
[sharedArray addObjectsFromArray:theObjectsToAdd];
[sharedLock unlockWithCondition:MYConditionStateHaveObjects];
And the receiver that should wait until the array has objects do this:
[sharedLock lockWhenCondition:MYConditionStateHaveObjects];
// ... Do something with the objects you got here
[sharedArray removeAllObjects];
[sharedLock unlockWithCondition:MYConditionStateNoObjects];
You can try using the following libraries: http://allseeing-i.com/ASIHTTPRequest/How-to-use and look for the asynchronous part
Asynchronous means that you won't block the main thread and wait for a response to come back.
If I got the idea, you need to handle the moment, when data from server was added to the array. So why you don't want to use KVO functionality? It will allow you to add observer which will listen for array content change.

iPHONE: TableView Scroll isn't smooth - What could be wrong?

I have a table view as shown. It displays various European Languages from database. When I scroll the tableview the scrolling isn't smooth and at times it gets stuck for a second or two. What could be wrong?
I am decoding the languages using below code:
NSString *cellText = [[langArray objectAtIndex:i] valueForKey:[NSString stringWithFormat:#"%#",lblshortName.text]];
if (cellText != (NSString *)[NSNull null] && ![cellText isEqualToString:#""] ) {
NSString *decodedString3 = [NSString stringWithUTF8String:[cellText cStringUsingEncoding:[NSString defaultCStringEncoding]]];
[cellTextArray addObject:[NSString stringWithFormat:#"%# : %#",lblshortName.text, decodedString3]];
}
else {
[cellTextArray addObject:#"<empty>"];
}
I would suggest to do few things..
Check if you are reusing the Cell, if you are then cross check it's working by putting counter for every new cell.
Use static analyzer and instruments for checking any potential leaks, memory allocations and objects are being freed or not.
if everything is fine.. then it's hard to say anything without seeing other part of the code..
one more thing you can do is using asynchronous thread to get data ready for the table view.
It would help if you provide more code, in particular how you use table-view cells, because table-view cells can easily cause performance issues.
Regarding your code, it seems like that the entire cellTextArray is built before presenting the table view, say, when you initialize the data source of the table view. Correct? Pre-building data could be good for the performance in general, but if the array is really, really huge so it causes a memory problem, then you might want to build texts dynamically.
More likely, however, I would check the followings first :
Are table-view cells property being reused?
Are subviews in the table-view cell opaque?
Aren't table-view cells drawing the entire region every time?
Aren't you unnecessarily calling drawRect: method directly?
I have seen such behavior when .layer property is being used in a lot places so, are you accessing the .layer property of a subview in the table cell or so?

One UITableViewController with many NSFetchedResultsControllers - bad idea?

My app involves a main screen with several sorting/viewing options of a set of data. Depending on what the user chooses, I may list them, e.g. alphabetically, N most recent, or grouped somehow.
I started the app as a Core Data Table-based navigation app; my app delegate sets up the Core Data stack (unchanged generated code), gives the NSManagedObjectContext to the controller for the initial screen, and it passes it to the UITableViewController implementing my "list of entities".
Since my three different views of the same data all end up showing a table listing out the data, I expanded this class to have three different NSFetchedResultsControllers, each with the one UITableViewController instance as their delegate. Before pushing this view controller on the stack, I call a method to switch which NSFetchedResultsController to use, e.g.
-(void)configureForMostRecent {
self.activeFetchedResultsController = self.mostRecentResultsController;
}
Now I am getting random crashes from Core Data, e.g. NSInternalInconsistencyException and other things like that. Sometimes, I use the app and everything's fine, other times, it crashes almost instantly.
So, my instinct is that my design is just a Bad Idea(tm).
Should I basically stick to a "One UITableViewController to one NSFetchedResultsController" sort of model and just use other coding styles to reduce boilerplate?
Using multiple NSFetchedResultsController instances is a perfectly valid design based on the description you have given so far.
Are you trying to use the same cache for each of these NSFetchedResultsController instances? Are you calling -reloadData on the table whenever you switch to a different NSFetchedResultsController? Both of those could be causing the crash you are seeing.
Update
The delegate is not an issue but not calling -reloadData is going to be a killer. The delegate methods really are there just to update the UITableView when the NSFetchedResultsController changes. The fact that a reference to is passed into those delegate methods is a hint that they are designed to handle multiple NSFetchedResultController` instances calling into them.
You could use one fetch controller, adjusting the fetch predicate and refetching as needed.
EDIT
Following my example case:
[NSFetchedResultsController deleteCacheWithName:#"MyObjectsCache"];
NSPredicate *_predicate = nil;
if (condition) {
_predicate = [NSPredicate predicateWithFormat:mySearchPredicateString];
self.currentTableView = searchDisplayController.searchResultsTableView;
}
else {
_predicate = [NSPredicate predicateWithFormat:myDefaultPredicateString];
self.currentTableView = tableView;
}
[fetchedResultsController.fetchRequest setPredicate:_predicate];
NSError *_error = nil;
if (![fetchedResultsController performFetch:&_error]) {
// handle error
}

addObserver questions, try to check if data is loaded

I have a ViewController that initializes another class that loads data into a mutable array and saves it as a property on itself.
here is my ViewController init code:
-(id) initWithCollectionID:(NSString *)aCollectionID {
if (self = [super init]){
collectionID=aCollectionID;
dataSource = [[CollectionListDataSource alloc] initWithCollectionID:collectionID];
}
return self;
}
once dataSource has loaded all of the data into it's property dataSource.collectionItems I set dataSource.loaded = #"true";
how do I use addObserver to watch that value and fire off a function in my ViewController?
something like this I'd assume:
[self addObserver:dataSource forKeyPath:#"loaded" options:NSKeyValueChangeNewKey context:nil];
Then what do I do?
As your code stands now, it will pause until the data is loaded regardless of whether you use notifications or not. It will not progress past:
dataSource = [[CollectionListDataSource alloc] initWithCollectionID:collectionID];
...until the CollectionListDataSource object has completed its own initialization (which I presume also means the loading its data) and returns an instance of itself.
If you want the CollectionListDataSource object to load while the view controller keeps on initializing, you will need to put the CollectionListDataSource object on another thread. However, you can't have an attribute object running on separate thread.
You seldom need to jump through such hoops. Unless this array is very large (10k+ objects) you most likely don't have to worry about. In most cases, you need the data before the view can function anyway so there's no point in letting the view go on without the data.
If you do need actually need to observe an attribute of another object, see Key-Value Programming Guide: Registering For Key-Value Observing for details.

numberOfRowsInSection did not return mutable array length

I am new to iphone development. numberOfRowsInSection method of UITableViewController executed before parsing the XML node so that this method return value as zero, but this method should be return value of number of rows with data.
please help me
thanks.
After parsing of your XML data is finished call [myTable reloadData]; - it will force your UITableView to reload the data shown and thus all necessary methods (including numberOfRowsInSection) to get called.
I've had a similar problem before, and it was because I was passing the array/dictionary to the controller from the appdelegate. Unfortunately, after the app delegate went out of scope, the array was lost.
Try doing an array copy,
NSArray data = [NSArray arrayWithArray: passedInArray];
Sorry, don't have my trusty macbook on me to check the code, but you get the drift.
I solved this problem via made connection between tableView reference and file owner in interface builder.