macOS剪贴板NSPasteboard
macOS剪贴板NSPasteboard

macOS剪贴板NSPasteboard

NSPasteboard 是 macOS(AppKit 框架)中的一个类,代表系统剪贴板(粘贴板),用于处理复制、剪切和粘贴操作的数据传输。

常见用途

1、⌘C / ⌘V 操作:拷贝或粘贴文本、图片、链接。

2、拖放功能:拖动文件到 App 中。

3、自定义格式共享:应用间传递特殊数据格式(如颜色、富文本)。

4、文件路径共享:拖入文件后读取路径。

常用属性

1、general:NSPasteboard类型,获取系统通用剪贴板(⌘C/⌘V 使用的)【静态属性】。

let pb = NSPasteboard.general

2、name:NSPasteboard.Name类型,当前 pasteboard 的名称(如 .general, .find, .drag 等)。

print(pb.name.rawValue) // "NSGeneralPboard"

3、types:[NSPasteboard.PasteboardType]?类型,当前剪贴板中包含的数据类型列表。

if let types = pb.types {
    print("剪贴板数据类型:\(types)")
}

表示当前剪贴板中有哪些数据类型,如:.string, .tiff, .png, .fileURL, .html。

4、pasteboardItems:[NSPasteboardItem]?类型,当前剪贴板的所有条目(用于多项支持)。

for item in pb.pasteboardItems ?? [] {
    print(item.types) // 查看每个 item 支持的类型
}

每个剪贴板 item 可以包含多个类型的数据(如同一项有文本 + HTML)。

5、changeCount:Int类型,当前剪贴板的版本号(每次写入会 +1)。

let count = pb.changeCount

每次调用 clearContents() 或写入数据时,这个数就会 +1,会随系统重启重置为0或初始值。

可用来监听剪贴板变化(结合 Timer 或 KVO),例如监听该值判断剪切板是否发生变更:

var lastChangeCount = NSPasteboard.general.changeCount

Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { _ in
    let newCount = NSPasteboard.general.changeCount
    if newCount != lastChangeCount {
        lastChangeCount = newCount
        print("剪贴板更新了")
    }
}

常用方法

一、读取数据方法

1、data(forType: NSPasteboard.PasteboardType):读取原始二进制数据(如图片、PDF);

2、string(forType: NSPasteboard.PasteboardType):读取纯文本类型内容(.string、.rtf 等);

3、propertyList(forType: NSPasteboard.PasteboardType):读取支持 Property List 的内容(RTF、HTML、URL 等),需要手动转型,在需要兼容老数据格式、数组、RTF、颜色时使用;

if let list = pb.propertyList(forType: .fileURL) as? [String] {
    print("剪贴板中的 fileURL 字符串为:\(list)")
}

4、readObjects(forClasses:options:):使用 UTType 类型读取多个 item(数组),用于读取URL、String、NSImage等类型,可替代propertyList;

if let urls = pb.readObjects(forClasses: [NSURL.self], options: nil) as? [URL] {
    print("用户复制的文件:\(urls.first!)")
}

5、canReadItem(withDataConformingToTypes:):判断是否存在符合某类型的数据。

示例:

let pb = NSPasteboard.general
if let imageData = pb.data(forType: .tiff) {
    print("图片数据大小:\(imageData.count) 字节")
}

二、写入数据的方法

1、clearContents():清除剪贴板所有内容(必须调用后才能写入);

2、setString(_:forType:):设置字符串(通常配合 .string);

3、setData(_:forType:):设置二进制数据(图像、PDF、HTML);

4、writeObjects(_:):让一组符合 NSPasteboardWriting 的对象写入剪贴板。

示例:

let pb = NSPasteboard.general
pb.clearContents()
pb.setString("Hello from clipboard!", forType: .string)

三、关于剪贴板条目的操作

1、pasteboardItems:获取所有剪贴板 item(每项可能支持多个类型);

2、numberOfItems:剪贴板中条目的数量;

3、availableType(from:):获取剪贴板中支持的第一个匹配类型。

四、系统剪贴板获取方式

1、NSPasteboard.general:系统通用剪贴板(大多数使用这个);

2、NSPasteboard.withUniqueName():创建一个唯一命名的临时剪贴板(适用于 App 内通信);

3、NSPasteboard(name: NSPasteboard.Name):创建自定义剪贴板;

4、NSPasteboard.Name.find:系统预定义名字,如 .general、.drag、.find、.font。

使用场景

1、NSPasteboard.general – 通用剪贴板

let pasteboard = NSPasteboard.general

表示系统的全局剪贴板(⌘C ⌘V 都用这个)。

2、写入文本(设置剪贴板内容)

let pasteboard = NSPasteboard.general
pasteboard.clearContents() // 清空旧内容
pasteboard.setString("Hello, world!", forType: .string)

3、读取文本(从剪贴板获取字符串)

if let str = NSPasteboard.general.string(forType: .string) {
    print("剪贴板内容:\(str)")
}

4、写入图片

let image = NSImage(named: "example")!
let pasteboard = NSPasteboard.general
pasteboard.clearContents()
pasteboard.writeObjects([image])

注意:图片必须符合 NSPasteboardWriting 协议(NSImage 已支持)。

5、读取文件路径(如拖入 Finder 文件)

let items = NSPasteboard.general.pasteboardItems
for item in items ?? [] {
    if let path = item.string(forType: .fileURL) {
        print("拖入文件路径:\(path)")
    }
}

6、读取图片

可以扩展测试多个图像类型:

let imageTypes: [NSPasteboard.PasteboardType] = [.png, .tiff]

for type in imageTypes {
    if let data = pb.data(forType: type),
       let image = NSImage(data: data) {
        print("粘贴的是 \(type.rawValue) 图像")
        pastedImage = image
        break
    }
}

支持的数据类型

1、.string:UTF-8 编码文本;

2、.pdf:PDF 文档;

3、.tiff:TIFF 图像;

4、.png:PNG 图像;

5、.rtf:RTF 富文本;

6、.rtfd:RTFD(带附件);

7、.html:HTML 内容;

8、.tabularText:表格文本;

9、.font:字体对象;

10、.ruler:标尺信息;

11、.color:NSColor 对象;

12、.sound:NSSound 对象;

13、.multipleTextSelection:多文本选择;

14、.textFinderOptions:文本查找选项;

15、.url:任意 URL;

16、.fileURL:本地文件 URL;

17、自定义类型:NSPasteboard.PasteboardType(“com.yourapp.custom”)。

注意事项

1、写入前要 clearContents():否则可能会有多个项干扰读取。

2、类型必须匹配:比如读取 .string 时,剪贴板里得有字符串类型。

3、支持多个 item:剪贴板可以存多个对象,用 .pasteboardItems 遍历。

4、多种用途:不只是拷贝粘贴,还支持拖放、服务菜单、Handoff。

总结

NSPasteboard管理剪贴板的对象,可以写入/读取剪贴板的内容。

如果想要支持原生生 ⌘V 快捷键监听,就需要使用NSEvent拦截⌘V,并在SwiftUI中响应。

如果不使用NSEvent,SwiftUI的TextField, TextEditor等组件可以响应⌘V,系统自动粘贴文本,对于SwiftUI自定义的视图则不会响应⌘V,就需要主动处理剪贴板。

相关文章

macOS用户输入事件NSEvent:https://fangjunyu.com/2025/07/04/macos%e7%94%a8%e6%88%b7%e8%be%93%e5%85%a5%e4%ba%8b%e4%bb%b6nsevent/

如何从剪贴板确定图像格式?

因为NSPasteboard的图像数据通常只有统一的public.tiff类型,不会保留原始的图片格式信息,也就是说:

NSPasteboard.general.data(forType: .tiff)

图像无论是从浏览器还是Photoshop获取,都只能获取获取的TIFF格式的Data数据。

此外,在Finder中复制图片文件时,粘贴板读取的实际是图标图像。

所以,可以尝试读取fileURL:

let pb = NSPasteboard.general
if let urls = pb.readObjects(forClasses: [NSURL.self], options: nil) as? [URL] {
    for url in urls {
        print("原始文件路径:", url.path)
        let imageData = try? Data(contentsOf: url) // 正确方式
        let fileExtension = url.pathExtension.lowercased()
        print("图片格式为:\(fileExtension),原始大小:\(imageData?.count ?? 0) 字节")
    }
}

拿到文件URL后,再读取文件原始内容。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注