3

I had this all working in Swift 3 and earlier but with Swift 4 no matter what variation I use this code will instead output text as a URL. If I put in "This is my sample text" the output after pasting the clipboard will be "This%20is%20my%20sample%20text". I have tried KuTTypeFileURL but that doesn't appear to make any difference either. What am I missing here? I have seen posts and discussions about how Apple is changing Pboards and other issues with sandboxing but I can't seem to figure this out at all.

original code what was working in swift 3 and earlier

private func copyToClipBoard(textToCopy: String) {
    let pasteBoard = NSPasteboard.general()
    pasteBoard.clearContents()
    pasteBoard.setString(textToCopy, forType: NSStringPboardType)

}

This gives an error of 'NSStringPboardType' is unavailable in Swift: use 'PasteboardType.string'

After searching online I came across these posts that describe the same issue and the workaround was to use the kuTTypeUrl as String

Found here stackoverflow.com/questions/44537356/… and here forums.developer.apple.com/thread/79144

When I try it this way it simply outputs as a URL when I just need a String.

@IBOutlet weak var nameTextField: NSTextField!

@IBAction func nameCopy(_ sender: Any) {
    copyToClipBoard(textToCopy: nameTextField.stringValue)
}


let NSStringPboardType = NSPasteboard.PasteboardType(kUTTypeURL as String)

private func copyToClipBoard(textToCopy: String) {
    let pasteBoard = NSPasteboard.general
    pasteBoard.clearContents()
    pasteBoard.setString(textToCopy, forType: NSStringPboardType)
}
Jeehut
  • 20,202
  • 8
  • 59
  • 80
kiddslopp
  • 95
  • 1
  • 8
  • 2
    If you don't want the string treated like a URL why are you setting the type as `kUTTypeURL`? Please put enough code in your question to fully demonstrate your issue showing how you want to set the string and how you read the string. – rmaddy Mar 10 '18 at 17:29
  • I updated the post with more information to explain why I am using kUTTypeURL. It was something I had found as a workaround when looking for a solution online. Sorry if I didn't provide enough information originally. – kiddslopp Mar 10 '18 at 17:53

2 Answers2

11

You are pasting an URL because you created a PasteboardType kUTTypeURL.

The solution is much simpler, there is a predefined string type

private func copyToClipBoard(textToCopy: String) {
    let pasteBoard = NSPasteboard.general
    pasteBoard.clearContents()
    pasteBoard.setString(textToCopy, forType: .string)

}

The note in the documentation

Apps that adopt App Sandbox cannot access files identified using the string pasteboard type. Instead, use an NSURL object, a bookmark, or a filename pasteboard type.

is related to files (aka string paths), not to regular strings

vadian
  • 274,689
  • 30
  • 353
  • 361
  • I originally had it coded this way in Swift 3 and earlier but now in Swift 4 I get an error "'NSStringPboardType' is unavailable in Swift: use 'PasteboardType.string'". After doing some digging online the workaround was to use the kUTTypeUrl. Found here https://stackoverflow.com/questions/44537356/swift-4-nsfilenamespboardtype-not-available-what-to-use-instead-for-registerfo and here https://forums.developer.apple.com/thread/79144 – kiddslopp Mar 10 '18 at 17:44
  • 1
    How can I copy font with font style? – Krunal Nagvadia Nov 14 '19 at 04:26
2

I just ran into a similar issue. My code looked like this:

NSPasteboard.general.setString("Hello World", forType: .string)

Unfortunately, this didn't work. But I figured there is a bug that if you don't store the NSPasteboard.general into a variable, the object created as part of the general computed property gets deinitialized before the setString change is propagated to the system.

So if you tried doing this in one line like me, just split it up to two instead, which worked for me:

let pasteboard = NSPasteboard.general
pasteboard.setString("Hello World", forType: .string)

I reported this bug via Feedback Assistant to Apple (FB9988062).

UPDATE: Apple answered my bug report, stating that you need to call declareTypes before setting a value, like so:

NSPasteboard.general.declareTypes([.string], owner: nil)
Jeehut
  • 20,202
  • 8
  • 59
  • 80
  • 2
    you need to put `NSPasteboard.general.clearContents()` on the line before `NSPasteboard.general.setString("Hello World", forType: .string)` – yes Jun 03 '22 at 07:24
  • @yes I just updated my answer with Apples official answer to my bug report. Can you elaborate why you would need to `clearContents()` first? Do you have a link to the documentation, for example? – Jeehut Jun 03 '22 at 07:59
  • 1
    `clearContents()`: "Clears the existing contents of the pasteboard, preparing it for new contents. This is the first step in providing data on the pasteboard." https://developer.apple.com/documentation/appkit/nspasteboard/1533599-clearcontents?language=swift `declareTypes(_:owner:)`: "This method is the equivalent of invoking clearContents(), implicitly writing the first pasteboard item, and then calling addTypes(_:owner:) to promise types for the first pasteboard item." https://developer.apple.com/documentation/appkit/nspasteboard/1533561-declaretypes?language=swift thats all i know – yes Jun 03 '22 at 08:13