Workaround for Swift scripts crashing after update to Xcode 11.4

If you have already updated to Xcode 11.4 that ships with Swift 5.2 you might have noticed that your Swift scripts all started crashing when accessing anything related to URL.

I use a script to generate a list of libraries used in the app and their licenses and running it now results in

Stack dump:
0.	Program arguments: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift -frontend -interpret test.swift -enable-objc-interop -stack-check -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -color-diagnostics -module-name test
1.	Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
2.	While running user code "fetch_licenses.swift"
0  swift                    0x000000010e62d4ea PrintStackTraceSignalHandler(void*) + 42
1  swift                    0x000000010e62ccc0 SignalHandler(int) + 352
2  libsystem_platform.dylib 0x00007fff71c8242d _sigtramp + 29
3  libsystem_platform.dylib 0x0000000000004936 _sigtramp + 2386044198
4  libsystem_platform.dylib 0x00000001172ce020 _sigtramp + 2774842384
5  swift                    0x000000010a3b09ba llvm::MCJIT::runFunction(llvm::Function*, llvm::ArrayRef<llvm::GenericValue>) + 458
6  swift                    0x000000010a3b7a2b llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*, std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > > const&, char const* const*) + 2011
7  swift                    0x000000010a38caea performCompileStepsPostSILGen(swift::CompilerInstance&, swift::CompilerInvocation&, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, bool, llvm::PointerUnion<swift::ModuleDecl*, swift::SourceFile*>, swift::PrimarySpecificPaths const&, bool, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 14362
8  swift                    0x000000010a3814a5 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 55813
9  swift                    0x000000010a2f74d3 main + 1283
10 libdyld.dylib            0x00007fff71a847fd start + 1
11 libdyld.dylib            0x000000000000000b start + 2388113423
fish: '/usr/bin/env xcrun swift fetch_…' terminated by signal SIGSEGV (Address boundary error)

This is a Swift bug that has been already reported.

Luckily I found a workaround!.

If you do not run the script directly with swift but instead compile it first with swiftc and then run the binary, everything works just fine.

Update: The problem is caused by having other tools that bundle Swift libraries installed on the system, like swiftlint and uninstalling them solves the crash.

macOS  Xcode 

Adding Wi-Fi and Bluetooth to hackintosh to enable Apple-specific features

When I started with my hackintosh I did not have Wi-Fi or Bluetooth support in it. I used Ethernet to connect to my home network and it worked fine, I had no need for Wi-Fi.

Later I wanted to use more “Apple-specific” features, so I started looking for how to make them work with my hackintosh.

Bluetooth

Adding Bluetooth support to a hackintosh is quite easy, you just need to buy any of these USB adapters:

All of them are natively supported in macOS, no extra drivers are needed.

GMYLE Bluetooth 4.0 Adapter

I bought the GMYLE Bluetooth 4.0 Adapter, found it on German Amazon.

Thanks to adding Bluetooth support I got:

  • Ability to use Bluetooth keyboards, speakers, headphones
  • SMS messages showing on macOS
  • incoming phone calls showing on macOS

The SMS relying feature was really nice, especially when needing to copy security codes sent by SMS by services that do not support 2FA via TOTP.

Justa s a side note, iMessage worked right from the start, Bluetooth is not needed for it.

Wi-Fi

Wi-Fi required for some Apple-specific features

The one thing that I was missing was AirDrop. I started taking screenshots regularly on my iPhone during development and testing and there was no easy way to move them to the hackintosh without AirDrop.

To make AirDrop and additional features like Handoff work you need not only Bluetooth but also an internal Wi-Fi card.

[Read More]

Editing macOS app About dialog

When you create a macOS app and keep the default menu, you automatically get an About dialog. This dialog shows basic info about the app.

If you want to add more information to this dialog there is no obvious way to do it. You need to start reading the Apple documentation to finally discover that it is actually quite simple.

[Read More]
macOS  Xcode 

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