NSTableView problems - displaying custom TableView from with a SplitView panel - objective-c

I am developing my first app for OSX. Sorry for asking stupid questions. I have spent a few hours trying to figure this out on my own, with no luck so far.
I want to make an iTunes-like interface. I used NSSplitView, placed NSView for navigation and NSTableView above that. [I am aware that there better alternatives to NSSplitView, yet my goal is to both - develop an app and also to learn Cocoa/OSX in the process.]
Atop NSView panel designated for navigation, I am trying to place NSTableView. However, my table is not being displayed. I therefore have questions...
I understand that for cells to be populated, controller must implement NSTableViewDataSource. I tried that, but was so far unsuccessful - to the point that I don't see the table. Please advise:
Can I have a working NSTableView-derived custom class also implementing NSTableViewDataSource? If this cannot work, please advise why or point me to an explanation.
Am I correct in thinking that all elements can be manipulated programmatically, in the sense that I use IBOutlet in headers to point to the right object, yet do nothing with InterfaceBuilder - have everything controlled from within my Objective-C code? Do I have to use IB?
Thank you.

Yes that will work but it's an unusual approach. Generally the tableview delegate/datasource is something enclosing the tableview. You'd normally only subclass NSTableView if you require some additional functionality not provided by default (for me that has been custom behaviour to input).
Yes you can do it all programmatically, however you will find it much easier to use IB. The IB-loaded views are created programmatically under the hood, using the information contained in the nib file. You will find it long-winded and tedious pretty quickly.
WRT to your issue with not seeing the table, you will need to add logging/breakpoints on the few key delegate/datasource methods to ensure they are being called (start with the daddy of them all numberOfRowsInTableView:). If they are not then you aren't setting the delegate/datasource correctly in the tableview.

Related

Why does NSTableView use NSCell instead of NSView?

This may be a general discussion instead of a real question. When I started using NSTableView and NSOutlineView, I thought : oh, a instance of NSView may do almost everything. So I return a NSView instance in my delegate and dataSource.
Of couse it did not work and I realized that NSTableView consitsts of instances of NSCell which inherits directly from NSObject.
I sensed that it may be important to understand why Cocoa constructed NSTableView based on NSCell but NSView. But few documents explain it clearly. Therefore I turn to Stackoverflow. Does anyone know that? Thank you at advance!
You can switch to a view based NSTableView or NSOutlineView in the inspector
The reason for a cell based cell would be if your only want to display a string. If you only want to display a string it would be a waste of resources to init a whole view to each cell. It is basically about memory control vs. what you need to display.
#d00dle's answer shows how to use an NSView backed table view, but it doesn't answer the question of why NSTableViews historically used NSCells in the first place.
The answer is that NSViews are heavy objects and expensive to manage. NSTableViews typically need many many rows and columns of "view-like" things, and if you naively added them all as actual NSViews, you can't maintain a responsive UI.
This is reflected in the trickiness Apple added to support NSView-backed table and outline views; it creates a limited number of NSViews and recycles them in clever ways to reduce the total number of NSViews in use at any given moment.

Split NSTabView across multiple NSViewControllers and XIBs

I'm just getting into desktop Cocoa development (I have experience with iOS development). If this question seems basic, forgive me.
That being said, I'm dealing with a large program with lots of calculations and functionality to deal with. There are almost a dozen views, organized with an NSTabView. Rather than dumping everything into one monstrosity of a class and creating a XIB file that brings my system to its knees (Xcode apparently isn't that efficient…who knew? :P). I'd like for each tab to be its own NSViewController with accompanying XIB; as such, I'd like to load each tab's view from the corresponding XIB.
I'm thinking of this in terms of UITabBarController, but this doesn't seem to work (there isn't an NSTabViewController as far as I could find). I'm not sure how to do this (or even if it's possible—but I can't be the only one with this issue?), and I'd appreciate any assistance. Thanks!
Update: I tried assigning the controller's view to the tab's view, but quickly realized that wouldn't get me anywhere. Is it worth creating an NSTabViewController from scratch, or is there a solution out there?
Cocoa development on the desktop has some major differences compared to iOS development. One of them is the use of view controllers - they aren't strictly necessary - and when you use them you can just stick to a generic NSViewController regardless of what kind of view it contains. All of the methods you need to control the tab view are in the NSTabView class - not the controller.
Having said that, putting 12 views in to a tabview sounds like a painful way to interact with a program. Have you thought about a source-detail type setup (think itunes or mail with their sidebars - each entry in the sidebar corresponds to a different view)?
I've ditched the tab bar, and as per sosborn's suggestion, I have used a split view—or rather I've put a table view on the side, and a custom view taking up most of the screen. Then, in my AppDelegate, I have individual controllers as ivars (I need individual controllers because there are a lot of calculations involved, and I don't want to have a monster class handling them all). They'll be lazily loaded, and the view will be assigned to the current controller's view as necessary.

Why must a split view controller always be the root of any interface you create?

In Apple's developer guide, they state: "A split view controller must always be the root of any interface you create" (see here). I was curious if anyone knew why they decided that. I have a tab navigator-based application and it makes sense for the content in one of the tabs to be presented in a split view. Why would Apple be opposed to that kind of design? Thanks in advance for your answers.
-Max
PS I'm not looking for ways to put a split view controller in a tab navigator controller (that much I can figure out, even if the code does look sloppy). I'm more curious if anyone has any idea why Apple frowns on it.
I don't think that this is necessarily a user experience decision as much as it is a technical restriction. UIKit makes a number of assumptions about how UIViewControllers will be used. Including the idea that only a single UIViewController instance has its view visible in given window at any given time. Now since Apple has access to the implementation they have been able to make exceptions for their own "container view controller" classes (UINavigationController, UITabBarController, and UISplitViewController). We can't tell exactly how much of a special case these controllers are or what they needed to do to support displaying nested sub view controllers correctly but one consequence seems to be that both UITabBarController and UISplitViewController are not intended to be used except as the root view controller of a window. Attempting to nest them within other container view controllers may cause unexpected or unreliable behavior.
I tried to cover these restrictions on the use of view controllers and some possible alternatives here: http://blog.carbonfive.com/2011/03/09/abusing-uiviewcontrollers/ Hopefully that's of some use to you but I'm afraid the only reliable way to get the UI you seem to be looking for it to implement your own split view style display within the view of a single UIViewController.
Please ignore my answer:
Because you can't resize UISplitViewController's subviews with touches?
Apple has always placed high value on consistent use of user interface elements. Having all applications work in the same way helps the user to immediately understand how an app works even if they've never seen it before. Establishing a conceptual hierarchy of view controller containers makes a lot of sense when you're trying to help the user predict behavior.

Best way to orchestrate multiple views in iOS without UITabBar or UINavigationBar?

I'm trying to create an iPhone app with a welcome screen that leads to two or three pretty disparate UIs; once you've drilled into one you're not going to have much use for the others, and each one is itself fairly complicated.
The designers are all web types and it looks like the "navigation" paradigm is the closest to what they want, but the breadcrumb-style navigation bar isn't.
If I set up a UINavigationController, can I then drive it with arbitrary buttons in the views?
And in general, is it possible to swap out the contents of a view programmatically?
And if so, what do I need to watch out for? (E.g., in Java if you change the contents of a JPanel you need to make sure it gets revalidated and repainted.)
Total iOS newbie here, coming from the Java world, super-explicit advice much appreciated. Using Monotouch, but happy to take Obj-C help and translate. :)
It's hard to tell you how to design your app with only that information, so I'll assume you want to do a drill-down thing like a UINavigation controller.
1- Yes, you can drive the UINavigationController from other ViewControllers, using methods like PushViewController() and PopViewController(). You can also hide the toolbar or some of the toolbar buttons if you want. You can find some great examples here.
2- Yes, you can change contents of a view. Views contains other views and you can add and remove them as you want.
3- The main thing to be careful about is to make sure that calls that update the view are done inside a InvokeOnMainThread(()=>{}) call. More info here.

Any "fundamentals-oriented" example of NSScroller out there?

I'm looking for some kind of a basic, straightforward example of how to work with a pair of NSScrollers in an NSScrollView with a custom NSView.
There are sporadic examples out there, largely consisting of contrived examples using programatically created interfaces, or based on the assumption that the developer is working with a typical ImageView or TextView. Even the Sketch example is based on an NSView that uses the Page Setup in the Print dialog for the bounds, and everything is managed by Cocoa. So there's no real discussion or examples anywhere of how make it all work using a custom Model (though that may be part of the problem, because what does one base the Model on?). Even Apple's own documentation is dodgy here.
Essentially, I have a sub-classed NSView enbedded in an NSScrollView (per the Scoll View Guide), that a user can click in the view to create, edit and delete objects, much like an illustration program. The Model is those objects that are just data wrappers that simply record their position for drawRect: to use. The height and width are based on custom values that are being translated into pixels as needed.
My problem is that all of the examples I have found are based on either a text editor, an image viewer, or uses the standard document sizes in the Page Setup dialog. Because these are common document types, Cocoa basically manages for the developer, so the interaction code is more or less hidden (or I'm just not seeing it for what it is). My project doesn't fit any of those needs, and I have no need for printing. Thrusting my Model into the documentView property wouldn't work.
I'm just looking for a simple example on how to initialize the NSScrollers with a custom, object-oriented Model (the documentView), and handle scrolling and updating based on user action, such as when the user drags a smattering of objects off to the left or down or the window gets resized. I think I'm close to getting it all together, but I'm missing the jumping off point that ties the controls to document.
(Not that it matters in a Cocoa question, but when I did this in REALbasic, I would simply calculate and apply the MaxX, MaxY to a ScrollBar's Maximum value based on user actions, watch the position in the ScrollBar when the user clicks, and draw as needed. NSScrollers in the NSScrollView context aren't nearly as obvious to me, it seems.)
I appreciate the time taken by everyone, but I'm updating with more information in the hopes of getting an answer I can use. I'm sorry, but none of this is making sense, Apple's documents are obtuse, but perhaps I'm missing something painfully obvious here...
I have an array of objects sitting in a subclassed NSDocument which are data holders that tell drawRect what and where to draw. This is straight from the Sketch example. The Sketch example uses the document sizes in the Page Setup dialog for the size, so there's nothing to show here. I'm cool with Cocoa handling the state of the scroll bars, but how do I link up the ScrollView to see the initial editor's state held in the NSDocument and updates to those objects and the editor? Do I calculate my own NSRect and pass that to the NSScrollView? Where and how? Am I doing this in my custom NSView which has been embedded in the NSScrollView or my NSDocument in init? The NSScrollView isn't created programmatically (there's no easy way of doing that), so it's all sitting in Interface Builder waiting to be hooked up. I'm missing the hook up bit.
Perhaps I'm wearing my "I don't get it" cap this week, but this can't be this difficult. Illustration apps, MIDI Editors, and countless other similar custom apps do this all the time.
SOLVED (mostly):
I think I have this sorted out now, though it's probably not the best implementation.
My document class now has a NSRect DocumentRect property that looks at all of its objects and gives back a new NSRect based on their location. I call it in my subclassed NSView's mouse events with
[self setFrame:[[self EditorDocument] DocumentRect]];
This updates the size of the View based on user interaction, and the window now handles the scrolling where it didn't before. At this point I'm figuring out how to get the frame to expand while dragging, but at least I now have the fundamental concept I was missing.
The answer given pointed me in the direction I needed to go here (documentView requiring a view, which translated to looking at the NSView class), so Peter gets the credit. Thanks so much for help.
The document view isn't a model, it's a view. That's why it's called the document view.
The reason there are so few examples on working with NSScrollers directly is because you normally don't. You work with NSScrollView and let it handle the scrollers for you.
All you need to do is make a view big enough to show the entire model, then set that as the document view of the scroll view. From there, it should Just Work. You don't need to manage any of the scrolling-related numbers yourself; Cocoa handles them for you.
For details, see the Scroll View Programming Guide.