Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"The Selector keyword has been deprecated in future versions of Swift" How can I create Keyboard Shortcuts in Dialog without an Edit Menu

Tags:

swift

The Swift 2.1 solution for Cut/Copy/Paste/SelectAll/Undo/Redo is here, but this now produces 6 warnings with Xcode 7.3/Swift 2.2. The Selector keyword has been deprecated in future versions of Swift.

Here is a partial solution, which compiles without warnings for Cut/Copy/Paste/SelectAll:

if NSApp.sendAction(Selector("cut:"), to:nil, from:self) { return true }

Becomes

if NSApp.sendAction(#selector(NSText.cut(_:)), to:nil, from:self) { return true }

However Undo/Redo still needs to be solved.

Attempt 1: This produces an error as NSText.undo does not exist

if NSApp.sendAction(#selector(NSText.undo(_:)), to:nil, from:self) { return true }

Attempt 2: This compiles but does not function:

if NSApp.sendAction(#selector(NSUndoManager.undo), to:nil, from:self) { return true }

Here is the entire code fragment:

class NSTextFieldWithKeyboard: NSTextField {

    private let commandKey = NSEventModifierFlags.CommandKeyMask.rawValue
    private let commandShiftKey = NSEventModifierFlags.CommandKeyMask.rawValue | NSEventModifierFlags.ShiftKeyMask.rawValue
    override func performKeyEquivalent(event: NSEvent) -> Bool {
        if event.type == NSEventType.KeyDown {
            if (event.modifierFlags.rawValue & NSEventModifierFlags.DeviceIndependentModifierFlagsMask.rawValue) == commandKey {
                switch event.charactersIgnoringModifiers! {
                case "x":
                    // New Swift 2.2 #selector works for cut, copy, paste and select all
                    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":
                    // Old method from Swift 2.1
                    // This functions, but produces the warning:
                    // No method declared with Objective-C selector 'undo:'
                    if NSApp.sendAction(Selector("undo:"), to:nil, from:self) { return true }

                    // Attempt 1: New use of Swift 2.2, but NSText.undo does not exist
                    //  Type 'NSText' has no member 'undo'
                    // if NSApp.sendAction(#selector(NSText.undo(_:)), to:nil, from:self) { return true }

                    // Attempt 2: Swift 2.2, but NSUndoManager.undo exists and compiles, but does not work
                    // if NSApp.sendAction(#selector(NSUndoManager.undo), to:nil, from:self) { return true }
                case "a":
                    if NSApp.sendAction(#selector(NSText.selectAll(_:)), to:nil, from:self) { return true }
                default:
                    break
                }
            }
            else if (event.modifierFlags.rawValue & NSEventModifierFlags.DeviceIndependentModifierFlagsMask.rawValue) == commandShiftKey {
                if event.charactersIgnoringModifiers == "Z" {
                    // The same warning we get with undo, we get with redo
                    if NSApp.sendAction(Selector("redo:"), to:nil, from:self) { return true }
                }
            }
        }
        return super.performKeyEquivalent(event)
    }
}
like image 213
Dave Avatar asked Sep 02 '25 17:09

Dave


1 Answers

Attempt #2 doesn't work because NSUndoManager has a method with the selector undo and not undo:.

I suggest you create a protocol to represent "an entity that responds to the undo action" and use that protocol to hold your selector:

@objc protocol UndoActionRespondable {
    func undo(sender: AnyObject)
}

let undoSelector = #selector(UndoActionRespondable.undo(_:))
like image 177
Scott Thompson Avatar answered Sep 04 '25 10:09

Scott Thompson