Three20 Empty Table View when Model is Not Finish Loading - iphone

The situation here is, I have an application with a tab bar, and each tab has a TTTableViewController with Datasource and TTURLRequest Models
When I do this series of actions, i get this no data table:
(1) While my fist view is loading, and the items is not yet displayed (Three20 Loading...)
(2) then I switch to another tab
(3) Then go back to that first view, I get an empty table. but when
I tried to breakpoint and look into the visible cells, the model, the datasource, they have values, but how come it displayed an empty table.

So here's a quick fix for my problem, i know this is not the best way.So what I did was to set a private boolean if it needs to invalidate the model, when user moves to another view and while the model is not yet loaded, i set the flag _isNeedtToInvalidateModel=YES
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(_isNeedToInvalidateModel) {
[self invalidateModel];
_isNeedToInvalidateModel = NO;
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if(![self.model isLoaded]) {
_isNeedToInvalidateModel = YES;
}
}
Somehow it does not show the empty table view anymore

Related

UITableView scrolling broken after clicking on a cell or other UI element

I have created a view controller, and added a table view as a subview to display data I fetch asynchronously from a web service. Initially the view displays an empty table. After the data is fetched, it is sorted, then stored in an array which holds the data for the table view. I call reloadData on the tableView at that point, and the data is displayed correctly. At this moment in time, the table view acts as it should (scrolling works as expected). However, as soon as I click on a cell, which takes me to a detail view controller (presented modally), when I return the table view has scrolled to the top, and scrolling is disabled (content still bounces however). The data is still there, if I drag up on the table cells, more are shown but snap back off screen once I let go.
Further complicating the issue is my custom split-view controller for changing the content displayed in the table view. It shows and hides itself with gestures, pressing an object in it will refetch the data in the main table view. At the point where the service finished loading the data and the table data has been refreshed, the table scrolls again as would be expected.
The app only supports iOS 6.0 and up for phone device types.
Here is some code that retrieves the data from the web service:
- (BOOL) getPatientVisits {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSDictionary *response = [[HMWebServiceFacade defaultFacade] getVisitListingForPatientId:appDelegate.selectedPatientId withUserCredential:appDelegate.usernamePasswordHash];
dispatch_async(dispatch_get_main_queue(), ^{
if ([[response objectForKey:#"status"] isEqualToString:#"OK"])
{
patientVisits = [[HMCommonUtils commonUtils] sortedArrayOfVisits:[response objectForKey:#"visits"]];
}
else if ([response objectForKey:#"RequestError"])
{
[[HMCommonActions standardActions] displayErrorAlertMessage:[response objectForKey:#"RequestError"]];
}
else
{
[[HMCommonActions standardActions] displayErrorAlertMessage:#"There were no visits for your loved one." withTitle:#"Sorry"];
patientVisits = nil;
}
[visitsTable reloadData];
[self viewWillAppear:YES];
});
});
return false;
}
In viewDidLoad I call [self getPatientVisits]; as well as in the callback function for any of clicked objects in the split-view.
You can set the scrollEnabled property of the tableView in the viewDidLoad method of the View.
Turns out the problem is with auto layout and iOS 6's table view headers. Using constraints in - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section causes this erratic behavior.

Caching data using UINavigationController

I am using the TableViewUpdates example from WWDC #2010. Basically Apple creates collapsable and expandable TableViews by clicking on the section header. The data for the TableView gets created in viewWillAppear like so:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/*
Check whether the section info array has been created, and if so whether the section count still matches the current section count. In general, you need to keep the section info synchronized with the rows and section. If you support editing in the table view, you need to appropriately update the section info during editing operations.
*/
if ((self.sectionInfoArray == nil) || ([self.sectionInfoArray count] != [self numberOfSectionsInTableView:self.tableView])) {
// For each play, set up a corresponding SectionInfo object to contain the default height for each row.
NSMutableArray *infoArray = [[NSMutableArray alloc] init];
for (Play *play in self.plays) {
SectionInfo *sectionInfo = [[SectionInfo alloc] init];
sectionInfo.play = play;
sectionInfo.open = NO;
NSNumber *defaultRowHeight = [NSNumber numberWithInteger:DEFAULT_ROW_HEIGHT];
NSInteger countOfQuotations = [[sectionInfo.play quotations] count];
for (NSInteger i = 0; i < countOfQuotations; i++) {
[sectionInfo insertObject:defaultRowHeight inRowHeightsAtIndex:i];
}
[infoArray addObject:sectionInfo];
[sectionInfo release];
}
self.sectionInfoArray = infoArray;
[infoArray release];
}
}
I've noticed for my case, where I have a lot of data, this is an expensive operation. I'd like to cache the data. The data gets created each time since it's in viewWillAppear. Because I'm using a UINavigationController to push this view onto the stack, if I put it into viewDidLoad, when I move away from this view and go back to home, I have to recreate the view again, viewDidLoad will run again, and it'll be slow again.
I haven't cached data before and was wondering what a good way to do it would be? Right now all of the data for the row headers and rows are in a database. So when this view gets pushed onto the stack, I grab the data, and create the table. I didn't know what a good mechanism would be to create the table and somehow cache the view or something to make it load faster on subsequent pushes of the viewController. Thanks.
The code you are showing is constructing the data source for the table view, and is not part of the view itself, per se. Wouldn't it meet your needs to execute this code in the view controller initializer and/or whenever your data source requires an update?
You can draw the parallel with NSFetchedResultsController and its delegate methods. These are executed apart form the view handling methods, with the fetched results controller being an ivar or (very often) a property of your view controller. Then, for example, once a fetched results controller has done its fetch, it can manage changes on a case-by-case basis, coordinated with the table view and its controller, or you can purposely refetch entirely. The view can appear and disappear completely independent of the data source maintenace.

Strange behaviour in viewWillAppear

I have a TabBar Controller with some tab bar item in it.
The first time that a user tap on a tab bar item, I want that a alertview is opened, so that the user can read some little instruction tips.
I have a global variable (say CONFIG), that hold some boolean valeus (CONFIG.tip1AlreadySeen, CONFIG.tip1AllreadySeen, etc.). All these boolean values are initializated to NO.
When the user tap a tab bar item, the viewWillAppear method in its viewcontroller is executed. In this method I put a code like this one:
-(void) viewVillAppear: (BOOL) animated {
extern CONFIG; // <- it's not the actual code but it indicates that a global variable must be used
[super viewWillAppear: animated];
if(CONFIG.tip1AlreadySeen == NO) {
CONFIG.tip1AlreadySeen = YES;
// code for showing the alertview
}
}
The strange thing is that this piece of code works perfectly in one viewcontroller but doesn't work in one another.
With some debug, I fidd out that in the another viewcontroller the code is executed but the assigment CONFIG.tipAlreadySeen = YES doesn't modify the actual value of CONFIG.tipAlreadySeen. This value is still NO. Unbelievable!!!
A little workaround was using the viewDidAppear method for changing the value:
-(void) viewVillAppear: (BOOL) animated {
extern CONFIG; // <- it's not the actual code but it indicates that a global variable must be used
[super viewWillAppear: animated];
if(CONFIG.tip1AlreadySeen == NO) {
// code for showing the alertview
}
}
-(void) viewDidAppear: (BOOL) animated {
extern CONFIG;
CONFIG.tip1AlreadySeen = YES;
}
...But I really did not understand what happened!!! Someone of you could explain this behaviour?
Thanks in advance!
Marco
Why must this be global and not contained in the view controller itself? Just a simple BOOL #property on your view controller that is toggled. And, to maintain this persistent across multiple runs of your application, save out the result to NSUserDefaults, which you in turn check each time you init your view controller.

“loading” spinner not leaving the TTTableViewController

I had a TTTableViewController used in iPad and initially I want it to be empty. When it first loads it actually calls:
- (id)initWithNavigatorURL:(NSURL*)URL query:(NSDictionary*)query {
if (self = [super init]) {
self.dataSource = nil;
}
return self;
}
However, the "loading" spinner stays in there and won't go away.
Why is this? I thought that this could happen because init wasn't called, but indeed it is.
I need some help.
When a TTTableViewController is presented on screen, it accesses it's model. If there's no model set, like in your case it creates a model in [TTModelViewController createInterstitialModel]. By default this will be a TTModel (the class not the protocol), which in turn does nothing then appearing to be loading.
In your createModel implementation you would need to create a model that does what you want and assign that to self.model.
Also note, that creating dataSources and / or model in the initializer is not optimal, consider creating your dataSources / models in createModel. They will be created only when needed (when the view appears on screen).

Reload the view in iphone (in viewWillAppear)

I got a little app that has a button whose click is handled via
- (IBAction)click:(id)sender { }
Now, what I want is after click() runs, I want the view to refresh/reload itself, so that viewWillAppear() is re-called automatically. Basically how the view originally appears.
Of course I can call viewWillAppear manually, but was wondering if I can get the framework to do it for me?
viewWillAppear is where to put code for when your view will appear, so it is more appropriate to put code that will be called repeatedly into another method like -resetView, which can then be called by both viewWillAppear and your click method. You can then call setNeedsDisplay from within resetView.
-(void)resetView
{
//reset your view components.
[self.view setNeedsDisplay];
}
-(void)viewWillAppear
{
[self resetView];
}
- (IBAction)click:(id)sender
{
[self resetView];
}