Get Values from NSTextFields in Subclassed NSTableView - swift

I have a reoccurring problem that I have not found a clean solution for. I have a NSTableView in NSViewController that uses a subclass of NSTableView to implement the datasource and delegate protocols e.g.
class SecondEdit: NSWindowController, NSWindowDelegate {
#IBOutlet weak var subTrackTable: NSTableView!
var sublist = SubTrackListing()
func loadTable() {
// other stuff left out for brevity
subTrackTable.setDataSource(sublist)
subTrackTable.setDelegate(sublist)
subTrackTable.reloadData()
}
in particular it should be noted that the XIB file for the WindowController contains the Table and the outlet for the table is connected to the NSWindowController class.
class SubTrackListing: NSTableView, NSTableViewDataSource, NSTableViewDelegate {
Usual NSTableView Delegate etc functions
}
This works like a charm and properly displays all of the data and keeps the required NSTableView functions in their own (smallish) class (desirable in as the Window / ViewController classes get pretty bloated by themselves).
My Problem is that I have NOT found a way to get user edits from the Table's texfields. IF the windowController class was also the NSTableView datasource / delegate, it would be trivial. I would just hook up the textfields IBActions and grab the sender stringValues. In the subclassed case, although you can hook up the IBActions just like before, THEY NEVER FIRE. I have tried setting the NSTableView subclass in IBs Custom Class dialog and putting the textfields in the SubTrackListing class, but not only does IB fight you on this every step of the way (you can't just drag from IB to the NSTableView subclass, you have to code the IBAction in the subclass first and then - sometimes - you can drag from the IBActions circle to the textfield in IB and get a recognized hook up), the IBAction - even when Xcode seems to think it's hooked up - NEVER FIRES (!). So I ask what the _____ !is going on here and how can you get NSTableView input from a subclassed NSTableView.
And yes I could just shove the NSTableView functions into the NSWindowController class, but not only would there be the what if you have more than one table situation, I have the general feeling that there Ought to be A Way to DO THIS in a subclass. . .
Any help would be appreciated. . .

Related

Swift difference between IBOutlet/IBAction and programatically constructing a view?

im kinda new to swift, and I don't understand what is the difference between the Interface Builder Outlet/Actions and programatically constructing a view. If I have IBOutlet why I don't need to still add them as subviews of the self.view and why do I don't need to instantiate them? As well, to not create two questions, why in the case of a creating a custom UiView I have to load the xib file with Bundle.loadNib?
Thanks,
You cannot initialize a property that is not nil by nature at instantiation time.
Interface Builder outlet, which always initializes after its owner. In this specific case — assuming it's properly configured in Interface Builder — you've guaranteed that the outlet is non-nil before you use it. That is why we can use as below:
#IBOutlet private var searchBar: UISearchBar!
Also, you already added subviews as well.
SearchViewController - ContentView - searchBar
That means ContentView or self.view is already superview of searchBar so you don`t need to add as a subview.
IBAction, IBOutlet, is responsible for connecting with objects on the Storyboard.
IBOutlet is a variable for accessing values, and IBAction can define an action on the event.
With Storyboard, prototypes can be created quickly and are easy to implement. However, if you work with multiple people, it can cause conflicts, so be careful.

Cannot add Outlet connection from Button to ViewController

I am trying to create an IBOutlet connection/reference from my button to my UIViewController in Xcode, but it is only giving me the "option" to add an Action connection. I am trying to utilize the viewDidLoad and baselineAdjustment to vertically center the buttons label when the text scales to fit the width, but am not having any luck.
Does anyone have a suggestion or know what I'm doing wrong?
EDIT: Adding a few more screenshots for clarity
If I select my main Scene View, the class is of type ViewController. If I select the view that the Button in question is a part of(it is in a ContainerView), it is of class UIViewController and the options do not present a choice of ViewController.
Make sure the right class subclassing the UIViewController, make sure when you are doing it, you choosing the UIViewController and not the View or the safe area.
Let me know if it solved it
I see the you have multiple ViewControllers in storyboard. Ideally, each View controller in the storyboard is supposed to be of only one type of UIViewController implementation and it's also true the other way around. so, If you have say 3 UIViewControllers in Your storyBoard, then you will need to create 3 .swift files which implement UIViewController like so:
abcVC:UIViewController { .....
efgVC:UIViewController { .....
ViewController:UIViewController { ..... //this is the default one you get.
and then set the class of each ViewController in your storyboard to one of each of the above.
if your ViewController which has the button you want to outlet has a class type abcVC, then you can outlet your button only in abcVc's implementation in abcVC.swift.
Hope it makes sense. to see how to set class, refer #Vadim F. 's answer.
and if you happen to upvote this answer, please also consider upvoting #Vadim F. 's answer.
This is how you can crate a new .swift file while subclassing a UIViewController: File -> new -> File -> Cocoa touch class -> #make it subclass of UIViewController and give it a unique name eg: abcVC
Certify that your ViewController in the Storyboard is of the class ViewController (i.e your view controller) and not from UIViewController.

Connecting NSTableView's delegate and dataSource to a custom subclass?

My app reads text files into [Card]. Each Card has a two-letter code at the front, and I break up the cards into different NSTableViews depending on that code. That lets me set the layout in IB so each group of cards has an appropriate display.
I used to have all of the controller code in a single VC, but as the number of tables grew, so did the complexity of this code. Since the views differ primarily in layout and some default settings, they can all descend from a single class. So I did:
class CardView: NSTableView, NSTableViewDataSource, NSTableViewDelegate { ...
and, for one example...
class GeometryView: CardView { ...
Then I went to IB, selected the tableview, and changed it's class to GeometryView. Now I have to set up the delegate and dataSource, and this is where I have my problem : IB will not allow me to drag either setting to either the GeometryView or CardView.
So... do the targets of these IB settings have to be a particular subclass, say NSViewController? Or is there something I'm missing that lets IB see these as targets? I didn't do anything in the original VC, it just worked. Or am I simply doing the wrong thing in IB?
In this image you can see the tableview on the far left, the custom view subclass in the helper, and the connections for the tableview on the right. Any attempt to drag from the connections to anywhere in the helper fails. Note that the two existing connections are to the former delegate VC, which is what I am trying to replace.
I'm not sure why Interface Builder won't let you connect the delegate or data source to itself, but you could do it programatically. The awakeFromNib method is probably the best place for this, as it's called after both initWithFrame and initWithCoder:
override func awakeFromNib() {
delegate = self
dataSource = self
super.awakeFromNib()
}

Does UITableViewController allow the table to be in a UIView?

UITableViewController seems to always hijack the View link in IB. So, if I put UITableView in a UIView and link up the View to that UIView, it still doesn't work. Only the UITableView is shown.
What I'd like to do is use a UITableViewController and put some labels on top of the uiTableView that can be hidden.. Like loading.. and No results found.
The only solution I have come up with is to resort to using UIViewController and then adding a UITableView link to the class and link it up in IB.
Am I missing something here?
It's fine to use a UIViewController, make it implement the table view datasource and delegate protocols, and then hook a UITableView up to it. It's also fine to have the controller's main view be a container UIView, and have a UITableView as a subview of that.
And yes, this is probably the best way to add some kind of overlay view, such as a message label. So I think you're on the right track.
You should also be able to do this using a UITableViewController, instead of a UIViewController that explicitly implements the table view protocols. I've had success with this. I'm not sure what you mean when you say that UITableViewController "hijacks" the view outlet in IB.
It really isn't a big deal either way. UITableViewController doesn't do much other than implement those protocols, provide a different default loadView method, and call [tableView reloadData] by default on viewWillAppear:. If you do those things yourself, you'll be fine.

UITableView and a UITextField that is always visible

I want to create an application which combines a chat feature. My question is this: how can I have a UITextField that is always visible in the same view as a UITableView?
The obvious solution would be to create my own UIView having a UITableView and a UITextField below it, however the UITableViewController doesn't seem to like me doing that as it expects the connected "view" outlet to be a UITableView, essentially destroying my plans.
Anyone with an idea?
Don't use UITableViewController. After all, it's just a standard controller with a full-screen UITableView. You can roll your own easily.
Use a standard UIViewController and have it implement UITableViewDelegate and UITableViewDataSource protocols (you don't need to implement every method -- just the required ones). Then give it a UITableView as an iVar and set the delegate and dataSource to self. Size it so it only takes half the screen and your other views take the other part. You can lay out the whole thing in IB or create and position view+table manually.
I would suggest sticking a regular view in between your controller and your smaller "half-views". That has usually cleared things up for me, or at least exposed what the problem might be.
If you don't need functionality that UITableViewController provided, than you can just use
UIViewController with <UITableViewDataSource, UITableViewDelegate> protocols.
So, your main viewController will accept any type of views.