UICollectionView content is hidden after reloadData - iphone

I have a UICollectionView that displays content from an NSFetchedResultsController. The collectionView has one section, and in that section there's a header. The header allows the user to filter the content in the collection view. The header view's delegate is connected to the UIViewController containing the collection view.
As soon as the user changes one of the filter options, the header view fires a message to its delegate. The delegate changes the predicate on the fetchRequest of its NSFetchedResultsController and calls -[NSFetchedResultsController performFetch:]. Next, the collection view has to be notified that the content has changed. This can be done in several ways, but the way I prefer is by calling -[UICollectionView reloadData]. Unfortunately this method does not work like expected: the entire collection view disappears when I call this method. These are some of the observations I made regarding this issue:
All cells and the header of the first (and only) section have their hidden flag set to YES. I tried to trace what method caused this by setting a symbolic breakpoint on -[UIView setHidden:]. Unfortunately it never breaks inside a UICollectionView subview.
collectionView:cellForItemAtIndexPath: is never called after calling -[UICollectionView reloadData].
collectionView:viewForSupplementaryElementOfKind:atIndexPath: is never called after calling -[UICollectionView reloadData].
numberOfSectionsInCollectionView: is still called and still returns the correct number (1 in this case).
collectionView:numberOfItemsInSection is still called and still returns the correct number (1 in this case).
What I have tried so far to solve the issue:
disabling all customizations (sectionInset, itemSize) on the UICollectionViewFlowLayout instance
disabling all customizations (separatorInset) on the UICollectionView instance
have the header added as a subview to UICollectionView and setting the contentInset accordingly. Unfortunately UICollectionView does not like me to temper with its auto layout constraints and crashes when I do so.
call [UICollectionView reloadSections:] instead of [UICollectionView reloadData]. This works but I don't like the animation.
manually insert, delete and update rows in the first section. This works as long as the view controller containing the collection view is in memory. As soon as it deallocates, the app crashes with an assertion failure in -[UICollectionView dealloc].
It does not feel right to have the header setup this way, but unfortunately UICollectionView does not have a global header like UITableView (tableHeaderView).

Try to Reload them in the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[self.collectionView reloadData];
});
it worked for me

Related

Scrollable all the way UITableView

I have this code linked to a button on a ViewController with a UITableView as subview:
-(IBAction)Action:(id)sender{
[tableView setContentSize:CGSizeMake(320, 1000)];
}
This makes tha tableView scrollable to the bottom so that I can use a couple of buttons I programatically added to the bottom. So far so good.
However, I want the tableView to be ok from the beginning, so I added the code inside viewDidLoad. Surprisingly, it doesn't work at all.
Could somebody give me a hand?
thanks!
If your datasource methods are being fired after viewDidLoad, the tableView content size will be reset when it's loaded. You'll need to make sure you've called reloadData for the table before the code above. If you're using a UITableViewController, the order the methods are called is:
viewDidLoad
ViewWillAppear:
<your datasource methods>
ViewDidAppear:
However, if you want buttons at the end of table, you should put them in the tableFooterView. You can do this in interface builder easily by dragging a view to the bottom of the tableView. Or you can do it in code (in your viewDidLoad method, for example)
Per #Justin's answer... your question isn't very clear
I'm not sure what your trying to accomplish. If your trying to access button on the bottom of a tableView why not use a Tableview Footer.
And if your trying to just scroll to the bottom of the tableview there is a method for that as well.
Need more info

Reload data in UItableview using a button

I want to add a refresh button in UINavigationBar that refreshes the entire table contents. Nothing happens when i click on the refresh button.
I searched google and found that reloadData method refreshes the tableview so I tried using it.
Are you sure your tableView outlet is linked correctly to your tableView property in Interface Builder ?
Is your internal datasource `refreshed' before you call reloadData?
-[UITableView reloadData] tells the table view to request again from you the number of rows in the table, and the cells at each section and row. It's up to you to update your internal data structures as appropriate. So in this case, your IBAction should call your own method to refetch the data from the server.
A few other notes:
Method names should have leading lowercase.
-initWithContentsOfURL: is blocking. This can hang your program for a long time. You should be using asynchronous fetching here (generally with NSURLConnection).
make sure you have the tableView outlet hooked up to the tableView.

viewDidUnload is not called for some view controller

I have a UITabBar with 2 view controller. The first one shows a UITableView, second one shows a UITextView.
When I click the first tab to show the tabview, and issue the memory warning in the simulator, the UITextView's didReceiveMemoryWarning is called automatically, however, the viewDidUnload is not getting called.
When I tap the second tab to show the textview, and issue the memory warning in the simulator, the first view controller's didReceiveMemoryWarning is called automatically, and the viewDidUnload is called as well.
So I want to know why the second view controller's viewDidUnload method is not called. Also, how can I make the first view controller(the one shows table view) viewDidUnload method is not called automatically when the app receive memory warning message.
Thanks.
Apple documentation implies that automatic view unloading only happens when the view was loaded from a named NIB file. If the UITextView view was created manually that would explain the unloading.
As to the second part, from what I've tried, there is no way to prevent the automatic unloading as it happens in the base class. If there is a way to create the view and "hide" the fact it came from a NIB, that might do it.

UITableView cellForRowAtIndexPath occasionally not called?

I'm developing a graphing application that on the main navigation/tab view displays a UIView that renders a graph using openGL. Beneath that view is a UITableView that displays the list of elements on the graph, and an add button.
Occasionally, when the user clicks on another tab, and then returns to the graph view tab, the table view does not get redrawn.
I have a [tableView reloadData] method being called in the navigation controllers' (also the table view's delegate and data source) viewDidAppear method.
numberOfSectionsInTableView and numberOfRowsInSection get called, but cellForRowAtIndexPath does not despite both latter methods returning positive values.
This is an intermittant problem, only happening some of the time, but it's not clear what (if anything) influences this.
Does anyone have any ideas?
[edit] Should just quickly add; clicking or otherwise interacting with the table view, whether faulted as described or not, ALWAYS causes it to be sucessfully redrawn.
[And again] A bit more information; when it faults as described, and calls the first two but not the cellforRowetc method, it seems to wait until the user interacts with the table before cellForRowetc is finally called (the first two methods are then not called) and is redrawn.
I had a UIActivityIndicator, started on a seperate thread, that showed when requests were being made to a web service. When the web service calls were completed, a notification was sent to the graph controller class to stop and hide the UIActivityIndicator. In this method, reloadData was being called on the table whether the view was visible or not, which seemed to be causing the problem.
The conclusion seems to be not to call reloadData on a table unless it's visible.

UITableView scrolling crashes App

Preface: I am new to the iPhone SDK, Obj-C, Interface Builder and Cocoa. I'm likely doing something obviously wrong.
Question:
I have a UITableView which crashes if I scroll it. It will scroll a little to reveal the full cell of the bottom most half-hidden cell, but won't load the next one. Similarly, if I scroll past the top to fully hide the bottom most cell, and it rubber bands back to show that cell, it will crash before showing it. This strikes me as odd because it is drawing the first 7 of 11 cells correctly. The cell data is in an NSArray, in a UITableViewController linked as both the dataSource and delegate for the UITableView in Interface Builder. It works when the view initializes.
I'm making an App I thought I'd be done with 2 days ago that just calculates combinations and displays a list of them in what I thought would be a convenient scrolling table view. Right now, it doesn't even calculate everything, the NSArray in the DataSource is initialized once with some strings like #"Hello" and #"World".
Steps to reproduce:
Because I'm using IB, I can't exactly show you the full story in code. So I'm going to describe what I did so far and hope it doesn't make you sleepy.
Made a new "Tab Bar Application" in Xcode, because I want 2 tabs, and I don't want a nav bar nor a full screen table. I moved the MainWindow.xib's first tab view out into FirstView.xib as an analogue to the given SecondView.xib. This worked nicely. I modified the view to contain two UITextFields for inputs, and a UITableView for output. This worked but the table was empty. I subclassed the UITableViewController wherein I populated an NSArray property named combinations with 11 strings, and then added
// Set up the cell...
cell.userInteractionEnabled = NO;
cell.text = [combinations objectAtIndex:indexPath.row];
where there had only been the comment. In IB I added a Table View Controller to the FirstView.xib and set it's class name to match the name of this new subclass, and control-dragged the Table View in my view onto this Combinations Table View Controller twice. Once linking the dataSource and once the delegate. Although I get the same behavior if only the dataSource is linked.
This runs and populates the table's visible rows (6.5) with the first 7 values in the dataSource combinations. I can scroll 0.5 cells down, and then back up. But if I scroll more than 0.5 cells up or down the app will crash. The explanation in the report reads:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -[NSCFTimer tableView:cellForRowAtIndexPath:]:
unrecognized selector sent to instance 0x52ca40'
I didn't make an NSCFTimer nor did I link it to my Table View, I suspect that the cellForRowAtIndexPath is exactly a message that should have gone to my dataSource or delegate so I'm confused at why it went astray and where it ended up going.
Update: Thanks for the answers and comments. My problem seems to be that the CombinationsTableViewController (subclass of UITableViewController) is actually not instantiated any particular place in my code. It does get created as some time (when the FirstView.xib is loaded) and is apparently managed while the initial tableView is filled with 7 cells, and is then released. So I need to identify where/how to make a retained reference to this controller. My Application Delegate should probably have some outlet that holds this controller that can be linked as the instance which is in the xib. Yeah, I'm new to this. I know I could just eliminate these troubles by avoiding the IB and doing things explicitly in code, but I figure I want to learn to use the IB flexibly.
Finally: Yes, I needed a retained instance of the table view controller. It sounds elementary, but this wasn't clear when working with the IB as I had. Read my own post for the whole process and fix.
Aside: Either the debugger needs detailed instructions (any links appreciated), or it doesn't work very well. I seem to get more information more quickly by letting the App crash and reading the report it generates. But this requires a tedious termination, relaunch, and 3 clicks. I had really wanted to move on from this to wiring up the inputs, doing the calculation, and updating the table with each change. That's supposed to be the hard part, not this making a framework member work stuff.
Further rambling: This was all in the iPhone SDK for 2.2.1. At the time iPhone OS 3.0 non-beta was not available yet without joining the club for cold hard cash. I expected it to be at the open of WWDC 2009, but it was actually today (July 17th 2009) that the free public 3.0 SDK was made available.
looks like you are losing your tableView delegate.
What looks like it is happening is the UITableViewDelegate is getting released and the app is then using the same pointer address for an NSCFTimer.
Have you called release on your delegete anywhere, or have you not retained the delegate if it is in an autorelease pool.
Okay so, if you followed the steps to reproduce I will now add the steps to solve this:
Steps to fix this problem
Subclass a UIViewController. I called mine CombinationsViewController. In this controller add a property as an IBOutlet for the combinationsTableViewController from step 6 below.
Don't forget to import the right stuff, and synthesize the table view controller, also release it in the dealloc method.
In FirstView.xib change the File's Owner class to this latest subclass.
Link it's combinationsViewController outlet to the Combinations Table View Controller in the FirstView.xib made in step 7 below.
Open the TabBarController in your MainWindow.xib select the first tab, and in the Identity Inspector change the class to the latest subclass (CombinationsViewController).
That makes the table populate normally and scroll stuff.
Now I'm going to move on finally and get some custom table view cell stuff happening and actually make my app do stuff.
Enumerated Steps to reproduce as a reference to the fix:
Made a new "Tab Bar Application" in Xcode.
Opened the Tab View Controller, dragged the prefab view for the first tab out into the MainWindow.xib
Made a new view based xib called FirstView.xib as an analogue to the given SecondView.xib, and put that prefab view into this xib.
Linked the view to the File's Owner's view outlet.
I modified the view to contain two UITextFields for inputs, and a UITableView for output.
I subclassed the UITableViewController as CombinationsTableView wherein I populated an NSArray property named combinations with 11 strings, and then added the cell.text = [combinations objectAtIndex:indexPath.row]; code where there had only been the comment about setting up the cell.
In FirstView.xib I added a Table View Controller and set it's class name to match the name of this new subclass, and control-dragged the Table View in my view onto this Combinations Table View Controller twice. Once linking the dataSource and once the delegate.
At this point the table does render with data, but the scrolling breaks. This is because the CombinationsTableView isn't retained anywhere. And that's very unclear to a first time IB user. So you need to apply the fix listed above.
The first person to summarize this in their answer get the correct answer check mark. E.G. Make a viewController subclass that is the file owner of FirstView.xib and contains an retained IBOutlet you can link to your table view controller in the same xib file.
The reason the first cell loads, is because the tableview pre-loads that like the other cells that are on screen.
All cells are loaded from the datasource method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
I would make sure that you have explicitely set the delegate and datasource of the tableView. This can be done in code or IB. by:
[self.tableView setDelegate:self];
[self.tableView setDataSource:self];
Also as Bluephlame said, you might be releasing the UITableVewController somewhere.
To find out, set a breakpoint inside the dealloc method:
- (void)dealloc{
//releasing things
[super dealloc];
}
If you do release it, you will hit this breakpoint. Then you can start to track down the culprit.
allocate memory to array instead of [NSArray arrayWithObjects:];. Without memory allocation it wont reload rows....use array=[NSArray alloc] initWithObjects]; ...instead of the above.
I had the same issue and fixed it by adding nil into an array as the last item.
It was crashing for this:
pairs = [[NSArray alloc] initWithObjects:#"EUR/USD",#"USD/JPY",#"GBP/USD",#"USD/CHF",#"USD/CAD"];
but not for this:
pairs = [[NSArray alloc] initWithObjects:#"EUR/USD",#"USD/JPY",#"GBP/USD",#"USD/CHF",#"USD/CAD",nil];
Hope this helps.
I had this same problem. I had a UITableViewController sub-class in a nib file, but I had only declared the UITableView as an outlet/property, which the tableview's UITableViewController was getting released while still in use.
The quick fix was simply to add an outlet to the File's Owner class that referenced the embedded UITableViewController.