Stop UIKeyCommand repeated actions

In general, you don't need to deal with this, since the new view would usually become the firstReponder and that would stop the repeating. For the playSound case, the user would realize what is happening and take her finger off of the key.

That said, there are real cases where specific keys should never repeat. It would be nice if Apple provided a public API for that. As far as I can tell, they do not.

Given the '//Not allowed in the AppStore' comment in your code, it seems like you're OK using a private API. In that case, you could disable repeating for a keyCommand with:

UIKeyCommand *keyCommand =  [UIKeyCommand ...];
[keyCommand setValue:@(NO) forKey:@"_repeatable"];

I reworked @Ely's answer a bit:

extension UIKeyCommand {
    var nonRepeating: UIKeyCommand {
        let repeatableConstant = "repeatable"
        if self.responds(to: Selector(repeatableConstant)) {
            self.setValue(false, forKey: repeatableConstant)
        }
        return self
    }
}

Now you can have to write less code. If for example just override var keyCommands: [UIKeyCommand]? by returning a static list it can be used like this:

override var keyCommands: [UIKeyCommand]? {
    return [
        UIKeyCommand(...),
        UIKeyCommand(...),
        UIKeyCommand(...),

        UIKeyCommand(...).nonRepeating,
        UIKeyCommand(...).nonRepeating,
        UIKeyCommand(...).nonRepeating,
    ]
}

This makes the first three command repeating (like increasing font size) and the last three ones non repeating (like sending an email).

Works with Swift 4, iOS 11.


This works in iOS 12, a little bit less 'private' compared to the accepted answer:

let command = UIKeyCommand(...)   
let repeatableConstant = "repeatable"
if command.responds(to: Selector(repeatableConstant)) {
    command.setValue(false, forKey: repeatableConstant)
}