NSCollectionView cell order changes on view change - objective-c

I have a macOS application that contains a tab bar design (ie: Tweetbot). There are 4 tabs that are linked to 4 different view controllers. The initial view controller (view one) contains a NSCollectionView which displays 3 cells horizontally.
This all works fine, however when I switch to another view controller and then come back to the initial view controller, the order of the collection view changes for no reason. I am not making ANY changes to the data source (which is a NSMutableArray) and I am not adding/deleting any cells, nor am I calling reloadData. I don't understand why the order of the collection view cells keep changing.
I have done some testing and can confirm that the order of the data in my data source, does NOT change at all. So it makes no sense for the collection view, to just change the order of the cells.
Another weird issue I have noticed, is that if I limit the collection view to 2 cells, this issue does not occur. This makes me wonder whether or not, the issue is down to some sort of NSCollectionView caching method that runs in the background? Perhaps when the collection view recycles a cell, it uses the incorrect data??
I have tried lots of different solutions, nothing seems to work. Does anyone have any ideas of what I can test/try out, in order to find out what's wrong?
Alternative idea
I could use NSTableView instead, because it supports multiple columns (unlike UITableView). So I could just make an NSTableView with 3 columns. Would this approach be any worse performance wise, than a NSCollectionView (especially if I wanted to add lots of cells?).

I couldn't find out what was wrong with the collection view. So I ended up using a NSTableView with multiple columns (instead of collection view rows). I set each column to have one row (index 0), which makes the table view look exactly like the collection view I was working with.
Performance wise the table view seems to be a lot better too. Even with hundreds of columns, it's still nice and smooth when scrolling/interacting.

Related

iOS 7 settings like DetailViewController

I have a simple project that was started from a Master/Detail template for iOS7.
I'd like to layout the detail view controller just like iOS settings. Do folks recommend using a table for that or just laying out the controls one by one?
Here is a screenshot of the effect I am looking for:
This is probably a matter of taste/opinion but I prefer tables for this kind of thing for these reasons:
You get all the nice features of tables right out of the box (efficient scrolling, cell reuse and delegate methods to handle where to push new view controllers on to the stack, etc...).
Flexible data model backed cell data. Your table view needs to be backed by some "settings" model object collection, obviously. That collection can be modified to include or exclude settings programmatically. Combine this with custom cells and you're off and rolling. This is really nice if your UI needs to change on the fly.
Code Reuse. If you have another set of "settings" you can use this data-backed table view approach and change only your data model. Doing this manually means you have a new view controller for every settings view. In your example picture, I'd bet my lunch that the 3 view controllers you see in that image are the same type of object.
The table's delegate methods are really helpful when segueing or pushing to new view controllers. Imagine having 10 settings that all took you to separate view controllers. You'd have to manually hook those transitions one by one, yuck.
Of course if you only have 1-2 settings that will never change, perhaps manual is the way to go. For my money, though, tables make sense because things like this always seem to change.

NSTableView: Displaying An Expanded Row (Resizing on the Fly)

OK. I looked through the suggestions (which often answer my questions before I ask). I haven't found what I need.
I know that I'm doing something wrong. I do this all the time in iOS (UIKit), but tables in NS (Mac) are pretty darn different from UIKit.
I have a view-based NSTableView. Each row has exactly 1 column. This column has a view with a header (21 points high), and an expanded view (the row is 420 points high). There is a disclosure triangle on the left of the header that toggles these two modes.
The controller is also the table datasource and delegate. I have the row height callback returning the correct values for the view.
The header displays fine. I set the row heights to 21, and only the headers are shown. This clips the main view.
When a disclosure triangle is toggled, a row expands its height to reveal the entire view:
Simple enough, eh?
The problem is that B is not displayed. I just get a blank (However, A is correctly displayed). The items are there, just not being displayed. The table row is the correct height (this can be verified by using alternating row colors).
I've tried setting setNeedsLayout/Draw on the views.
Any clues on what I may be doing wrong?
I'm willing to bet that I'm doing something boneheaded, and I'll keep looking into this.
Using noteHeighOfRowsWithIndexesChanged:? It's an NSTableView function, not a delegate function.
In the documentation for the delegate function tableView:heightOfRow it declares:
Although table views may cache the returned values, you should ensure that this method is efficient. When you change a row's height you must invalidate the existing row height by calling noteHeightOfRowsWithIndexesChanged:. NSTableView automatically invalidates its entire row height cache when reloadData and noteNumberOfRowsChanged are called.
As it mentions, NSTableView's reloadData is often the lazy way to fix your sort of issue as well.
Your table controller shouldn't need the setsNeeds[whatever] methods you tried.
Also, speaking of disclosure triangles and such, on OSX there is a NSTableView subclass called NSOutlineView that handles item expansion if you mangle your data into a poorly documented tree format. I actually wouldn't recommend it if your data's not a natural tree, but you should be aware of it, even if its API sucks. Oh, and the expansion when clicking the disclosure triangle is animated.

iOS7 UITableview slow on reloading section/row

My tableview that used to smoothly reload the sections and rows is now slow when running on iOS 7. When I reload the whole tableview table is loaded instantaneously, but calling reloadRowsAtIndexPaths or reloadSections (with UITableViewRowAnimationNone) takes somewhere around a second to complete.
I'm not using AutoLayout for this section of the app yet. The cells are laid out in separate Xib files with the corresponding custom classes
Do you have auto layout enabled for your cell views? Are you reloading your table view when it is not visible (for instance, when a detail view controller is pushed)? This seems like a known bug. See this question/answer. Apple bug report: rdar://15175803
Basically, you have a multi tiered solution, which is not perfect but will give you satisfactory results. First, this is always true, optimize your constraints in the table view cell. If you have constraints modified dynamically, make sure you are not causing needless layouts and drawing. Second, do not update your table view if it is not visible. This feels like a hack, but there is no other option (well, there is one, but it involves disabling auto layout, which is not optimal at all, so let's ignore). You can test in your view controller if the tableView.window property is nil, which would indicate that the table view is hidden. If it is not hidden, update normally, but if it is, do not update. Just set a flag that the table was updated. On viewWillAppear: call reloadData to update the table. You can preserve selection by querying the table view for selected indexpaths and selecting them again after reloading the data.

Two UICollectionView instances sharing the same UICollectionViewFlowLayout instance?

I'm not sure if this is a feature or a bug, but when I have two collection views on a view controller using the same instance of UICollectionViewFlowLayout, an interesting thing happens. Note that I'm not using Interface Builder / XIBs for any of this; I'm laying everything out in code.
The first UICollectionView has twelve cells in it, but the second one has 20. When I reload both collection views, both act as if their contentSize property has 20 cells in it. This means that when I scroll to the right of the first UICollectionView and get past the first (and only) 12 cells, my app crashes (because I'm pulling data from an array that only has 12 cells' worth of data).
To get around this for now, I'm instantiating two identical UICollectionViewFlowLayout objects and assigning each to its own collection view. Is this normal behavior?
I'm only getting started writing code with UICollectionViews, so forgive my ignorance if I'm exuding any!
Don't do this. A collection view and a layout object should be a 1:1 relationship. The layout object has a property, collectionView, which obviously can only hold a reference to one collection view.
When the collection view then asks the layout for its size and so forth, the layout object is going to base everything on the second collection view you assigned the layout to, since this will be held in the collectionView property.
I couldn't find an explicit statement in the docs not to share a layout object between collection views, but the property discussed above should make it clear that this is not an intended use.

UITableViewController Dynamic Drill-Downs

In a table-view that contains say 10 cells, is it the case that we need to create 10 separate UITableViewControllers to handle the different views loaded by clicking on each of those 10 cells?
That doesn't seem very efficient - especially in situations where large amounts of data (and thus tables/menu) need to be displayed.
How can you write a dynamic UITableViewController, that can accept any data-set (like an Array) on the fly and display its contents - and do it in a recyclable manner, so that it can be recreated again and again for each cell that is clicked?
I have it mostly working in an app I'm building - the only thing I don't fully understand about the method is how the incrementing of the "CurrentLevel" works since it seems like the variable would just keep getting reset since the controller calls itself.
Anyhow, the concept is that every time someone clicks a cell, a new instance of the UITableView controller is called and a new level is generated and added to "the stack", and a navigation controller is able to track what is in the stack and allow you to browse back to the previously loaded views.