display rowActions in NSTableView OS X - macos

I want to create a swipable tableview same as it is present in the IOS. But I am not able to find any document related to that. Also I was going through the NSTableView Documentation and fund the following.
/* View Based TableView: rowActionsVisible can be queried to determine if the "row actions" (see: tableView:rowActionsForRow:edge:) are visible or not. Set rowActionsVisible=NO to hide the row actions. Setting rowActionsVisible=YES is currently not supported and will throw an exception. This property is not encoded in the nib.
*/
#property BOOL rowActionsVisible NS_AVAILABLE_MAC(10_11);
At the end of the Comment it says Setting rowActionsVisible=YES is currently not supported and will throw an exception. So, how are we going to set the action?
Any leads would be appreciated.

So the new Swipeable table functionality was added in MacOS 10.11, and it looks like the way to do it is via implementing the NSTableViewDelegate method:
optional func tableView(_ tableView: NSTableView, rowActionsForRow row: Int, edge edge: NSTableRowActionEdge) -> [NSTableViewRowAction]
Where you can set up NSTableViewRowAction objects via a relatively straightforward init method.

Related

NSTableView Delegate Methods aren't getting called by .reloadData()

This one is stumping me, though I know it's going to be simple.
I have multiple ViewControllers, each of which has a table view to display a list of data specific to the controller. Three out of the 4 work perfectly. However, I'm clearly missing something in the forth, because the Delegate methods are never getting called by .reloadData(). No compiler errors, just never calls my delegate methods for some reason.
Here is my class setup including my connected outlet variable:
class performanceViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
//--------------------------------
// OUTLET CONNECTIONS
//--------------------------------
#IBOutlet weak var displayPerformanceList: NSTableView!
I've also implemented the following two delegate functions:
func numberOfRows(in tableView: NSTableView) -> Int {
and
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
but for some reason, neither of these functions are called when I execute my custom function:
func redrawViews() {
self.displayPerformanceList.reloadData()
}
(Note: the .reloadData is wrapped in a function because it will be doing other things as well that I haven't added in yet.)
I added breakpoints in both of the delegate functions, which is how I know they are not getting executed.
I know this is going to turn out to be something stupid that I missed since I have it working in three other custom viewControllers... I just can't for the life of me figure out what I missed...
Any thoughts would be greatly appreciated!
:)
Well, after poking around a bit more and following some tutorials, I found my problem. I completely forgot to link the NSTableView Data Source and Delegate to the controller in the Interface Builder!
Doh!
Leaving this question/answer here in case anyone else gets caught by this. :)

NSCollectionView or NSTableView automatic height adjustment of cells

In iOS you could use:
self.tableView.rowHeight = UITableViewAutomaticDimension
to achieve automatic height adjustment of cells.
Is there any way to achieve this behaviour in macOS with NSCollectionView or NSTableView?
Talking about NSTableView... As of El Capitan there was no easy way to do this. Not sure about new Sierra SDK.
From my experience, the most reliable way to regulate table row's height is to use NSTableViewDelegate method:
func tableView(tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
//Here you do some magic measuring actual content of the cell and returning heigh
}
The only positive thing is that some controls have: fittingSize property and can simplify process.
Also, dynamic content change will require you to call noteHeightOfRowsWithIndexesChanged method of table view, to cause that delegate method be called again where your code will recalculate new height.
With macOS 11 and newer, the situation is as follows:
NSTableView can now actually use auto layout to achieve automatic height adjustment of cells. You must properly configure your cell template(s) to use auto layout, and you must instruct the table to use auto layout (can also be done in the storyboard) for row height calculations:
tableView.usesAutomaticRowHeights = true
NSCollectionView is currently (2021) still behind in features compared to the iOS counterpart, and still doesn't support any tableview feature like automatic row heights.

Setting a Variable "as" a Class

func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerCell = tableView.dequeueReusableCellWithIdentifier("HeaderCell") as! CustomHeaderCell
You can see the code above. I just wanted to ask that how and why we can, or should, set a tableViewCell as a Class? In this case it is CustomHeaderCell. For further info about the code here's the thing: I am just creating a custom header by following a guide I saw in web.
You should use this pattern when (a) you know the actual class of the object being returned, whereas the compiler can't reasonably know this; and (b) you need to then use the methods/properties of this subclass.
In this case, you probably have a cell prototype in your storyboard that specifies a CustomHeaderCell base class (or you have registered a class or NIB such that you know that the HeaderCell identifier will return a CustomHeaderCell instance). Furthermore, you presumably want to reference the properties of this CustomHeaderCell (e.g. setting the text property of its custom UILabel outlets or whatever).

How to show necessary methods to be implemented for specific protocol

I am absolute beginner with IOS and XCode and swift and I am doing my first tries with Xcode in a Yosemite built in a Vmware running under Windows7 (guest is MAC yosemite, Host is windows running vmware workstation 9 )
I have a ViewController Class in my IOS project declared as follow:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {...}
Now I would like to implement the necessary methods of the protocols UIViewController and UITableViewDelegate.
In a tutorial
http://jamesonquave.com/blog/developing-ios-apps-using-swift-tutorial/
it says I have to use Command+Click on a protocoll to show which methods should be implemented.
I don't know howto do "command+click on the protocoll" this with my vmware.
any hints ?
When using Alt+clicking on a protocoll it shows me the help. If I am WindowsButton+clicking on a protocoll it opens a new window with sourcecode of the protocoll. Now howto show methods, which should be implemented.
To help you out, UIViewController is a class, which you are subclassing. It is not a protocol, so it doesn't have any necessary methods for you to implement. You can however override the methods you inherit, which is what you see in when you first create the file, ex.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
This overrides the method you inherited from UIViewController. If you aren't doing anything other than calling super.viewDidLoad() you can remove the entire function from your code.
Now UITableViewDataSource and UITableViewDelegate or both protocols, so they may or may not have required methods to implement.
What you describe when you alt-click, is the same as if you right clicked on UITableViewDataSource and selected jump to definition. This is what you get when you command click on an actual Mac. What the tutorial is saying is that the required methods will be at the top, which isn't always the case if you look at the documentation (as the methods are organized more by purpose there). In the case of UITableViewDataSource, you should see something like:
protocol UITableViewDataSource : NSObjectProtocol {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
optional func numberOfSectionsInTableView(tableView: UITableView) -> Int // Default is 1 if not implemented
optional func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? // fixed font style. use custom view (UILabel) if you want something different
optional func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String?
You will notice that the first two methods func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int and func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell do not have optional in front of them. This means that these are the required methods for this protocol. The optional ones below that are optional.
In the case of UITableViewDelegate you'll see that there are no non-optional methods, and therefore it does not require you to implement any.
You are doing the right thing when you windows click the protocol name to jump to its definition, which is basically just a list of all its methods you can copy and paste into your code
Edit
the below is for changing keyboards:
You could try swaping the keys like this:
I don't like putting external source links because they sometimes dissapear so below is the text in their how to:
To swap the Option/Alt key and the Command/Windows key:
Fusion 2.x and later
Go to VMware Fusion > Preferences.
Click Keyboard & Mouse, and then Key Mappings.
Find the line that has a Mac Shortcut of Option,
and double-click it to edit it.
If you don't see this line, click the + button and then select
Option in the top row of keys.
In the To mapping in the bottom row of keys ensure that Alt is not
slected and that the Windows logo is selected.This will ensure that
pressing the Option key will send the Windows key to the virtual
machine.
Click OK.
Find the line that has a Mac Shortcut of the
command key logo, and double-click it to edit it.
If you don't see this line, click the + button and then select the
command key logo in the top row of keys.
In the To mapping in the bottom row of keys ensure that the Windows
logo is not selected and that Alt is selected.This will ensure that
pressing the Command key will send the Alt key to the virtual
machine. Click OK.
Fusion 1.x
Shut down your virtual machine and quit Fusion.
Navigate to [Macintosh HD]//Library/Preferences/VMware Fusion
Ctrl-click the config file and select Open with.
Select TextEdit and click Open. Add the line:
-mks.keyboard.swapAlt = TRUE
When your virtual machine starts, the Option/Alt key and the Command/Windows key are reversed.

How to move data across view-controllers? In a simple Swift-iOS8 way

I've read plenty about the How-To about moving data across view-controllers in Swift iOS programming but so far I haven't found a big consensus:
Temporary models (Unnecessary I think for small data)
Variable/Placeholders
Protocols
Others...
The rules about references and pointers in Objective-C may not apply for Swift, so values flying over in memory with protocols may not be the same, or I don't know (that's why I'm asking).
So, in a very simple but well-done manner, if I have a variable say... - result - of String type in a ViewController1 how can I make it available in a ViewController2? I don't need an Strong link to it, just the value.
Which way would you recommend?
Thank you all very much for your answers.
A common way to "jump" from viewController1 to viewController2 is via a storyboard segue. This segue can be performend in several ways: Directly from storyboard (i.e. from a button) or by code, using performSegueWithIdentifier method from a UIViewController.
No matter which way the segue is performed, the method prepareForSegue is called immediately before the segue is performed. In this method you get a reference to the segue's target viewController where you can pass your variable.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController2 = segue.destinationViewController as ViewController2 {
// passing variable from vc1 to vc2
viewController2.result = self.result
}
}

Resources