Detecting click on a specific NSTableViewCell

When you use NSTableView in an macOS application, there is no direct way to know a specific NSTableViewCell was clicked by the user. In my Localization Editor project I wanted the user to be able to focus a NSTextField when clicking anywhere in the NSTableViewCell it is contained in, so I had to implement it myself.

I created a new delegate extending the NSTableViewDelegate with one additional method informing about a NSTableViewCell getting clicked

protocol NSTableViewClickableDelegate: NSTableViewDelegate {
    func tableView(_ tableView: NSTableView, didClickRow row: Int, didClickColumn: Int)
}

Then I added an extension to the NSTableView to compute the index of the clicked NSTableViewCell

extension NSTableView {
    open override func mouseDown(with event: NSEvent) {
        let localLocation = self.convert(event.locationInWindow, to: nil)
        let clickedRow = self.row(at: localLocation)
        let clickedColumn = self.column(at: localLocation)

        super.mouseDown(with: event)

        guard clickedRow >= 0, clickedColumn >= 0, let delegate = self.delegate as? NSTableViewClickableDelegate else {
            return
        }

        delegate.tableView(self, didClickRow: clickedRow, didClickColumn: clickedColumn)
    }
}

To be able to use this extension you just need to implement NSTableViewClickableDelegate instead of NSTableViewDelegate and use the additional method it provides.

macos  swift 

Making copy & paste work with NSTextField

When I started working on my open-source Localization Editor, which is a macOS application, I encountered some things that were a bit strange compared to iOS development. One of those things is that copy & paste does not automatically work on a NSTextField.

To be exact, copy & paste works on a NSTextField as long as you do not delete the Edit menu from the standard Main menu. If you do that for some reason, you have to implement all the copy & paste functionality yourself.

The key to the implementation is overriding the performKeyEquivalent method and manually checking for cmd + c/v/x/z/a

final class EditableNSTextField: NSTextField {

    private let commandKey = NSEvent.ModifierFlags.command.rawValue
    private let commandShiftKey = NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue

    override func performKeyEquivalent(with event: NSEvent) -> Bool {
        if event.type == NSEvent.EventType.keyDown {
            if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue) == commandKey {
                switch event.charactersIgnoringModifiers! {
                case "x":
                    if NSApp.sendAction(#selector(NSText.cut(_:)), to: nil, from: self) { return true }
                case "c":
                    if NSApp.sendAction(#selector(NSText.copy(_:)), to: nil, from: self) { return true }
                case "v":
                    if NSApp.sendAction(#selector(NSText.paste(_:)), to: nil, from: self) { return true }
                case "z":
                    if NSApp.sendAction(Selector(("undo:")), to: nil, from: self) { return true }
                case "a":
                    if NSApp.sendAction(#selector(NSResponder.selectAll(_:)), to: nil, from: self) { return true }
                default:
                    break
                }
            } else if (event.modifierFlags.rawValue & NSEvent.ModifierFlags.deviceIndependentFlagsMask.rawValue) == commandShiftKey {
                if event.charactersIgnoringModifiers == "Z" {
                    if NSApp.sendAction(Selector(("redo:")), to: nil, from: self) { return true }
                }
            }
        }
        return super.performKeyEquivalent(with: event)
    }
}
macos  swift 

Switching my Hackintosh from NVIDIA to AMD because of Mojave

When I turned my computer into a Hackintosh about 2 years ago I was using an NVIDIA GTX 660 as my GPU and it worked without any additional drivers because of built-in support in Sierra. When I later bought a 4K display I could not make the GTX 660 drive the display at 4K@60Hz in macOS, although it worked well in Windows.

NVIDIA web drivers

I decided I needed a more powerful GPU anyway to play games on the new display in Windows so I bought a GTX 1060. It worked in Sierra and High Sierra thanks to the so called web drivers; GPU drivers provided my NVIDIA on their website. Without the web drivers you get no hardware acceleration, no 4K as maximum resolution, just one display working … the whole setup is basically unusable.

Those web drivers are version specific, every time the macOS build number changes after some update you need new ones (or to use a script to patch the previous ones). This is a bit annoying, you typically have to wait a few days after every macOS update for new drivers to become available and update then.

No web drivers for Mojave

When a new major version of macOS comes out, like Mojave, you cannot use web drivers for the previous version. NVIDIA needs to release new drivers and they now cannot do it without cooperation from Apple. Citing from the NVIDIA Developer forums

Developers using Macs with NVIDIA graphics cards are reporting that after upgrading from 10.13 to 10.14 (Mojave) they are experiencing rendering regressions and slow performance. Apple fully controls drivers for Mac OS. Unfortunately, NVIDIA currently cannot release a driver unless it is approved by Apple.

Apple basically blocks NVIDIA from releasing web drivers for Mojave, that is the reason the drivers are not out even now half, a year after Mojave release. If you are for example an iOS developer, XCode 10.2, the next version of Xcode, will only run on Mojave and you will not be able to use it unless you upgrade.

AMD GPUs in Mojave

Mojave natively supports some GPUs from AMD. You can buy a RX 560, RX 570, RX 580, Vega 56 or Vega 64 and it should work out of the box, no extra drivers needed. You not even have to install Lilu or Whatevergreen.

[Read More]

Debugging iOS network traffic

When working on an iOS app you may sometimes need to inspect or debug the network traffic between the app and the server to see what exactly is going on. Or you may be just curious to see what data other apps send about you to their servers. The way to achieve this is to run a proxy on your computer and route all the traffic from your iOS device through that proxy.

mitmproxy

Mitmproxy is a free and open source interactive HTTPS proxy. The UX is not as great as in paid app like Charles, but it is still good enough.

Installing and running

You install mitmproxy from homebrew

brew install mitmproxy

and run the command line interface with a simple mitmproxy proxy command. The command line interface takes some time to get used to. If you want something simpler, run the mitmweb command to get a web interface.

Setting up the iOS device

Proxy

When you have mitmproxy or mitmweb running you now need to set your iOS device to use that proxy. On your iOS device, go to Settings | Wi-Fi and to the properties of your Wi-Fi network. Switch the HTTP Proxy to manual and set the it to the IP address of your computer running mitmproxy and port 8080.

[Read More]

Using CloneZilla for regular hackintosh backups

If you are a macOS user you may be used to Time Machine as the standard for backups. Time Machine is fine if you want to backup your files and configuration, but if for example your disk dies or your hackintosh completely breaks with some bad update, there are better and faster ways to get it up and running again.

Requirements

Basically everything comes down to your backup requirements. These are mine

  • full backup of the macOS SSD including EFI with Clover
  • backups that can be restored without any additional configuration to the current macOS SSD or a new one in case of a disk failure
  • no need for the ability to restore single files (all work data are in Git and Dropbox)
  • reasonable backup and restore speed

Looking at different backup solutions I chose Clonezilla. It is not exactly the most user-friendly solution, but it is a very powerful one if you know what you are doing.

[Read More]