Как скопировать текст в буфер обмена (UIPasteboard) на Swift?
Копирование текста в буфер обмена с помощью UIPasteboard
Ваш код в целом верен, но есть несколько нюансов, которые стоит учесть. Основной класс для работы с буфером обмена в iOS — UIPasteboard. Его синглтон general предоставляет доступ к системному буферу обмена. Вот правильный и полный пример для кнопки:
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var copyButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Дополнительная настройка, если нужно
}
@IBAction func copyButtonTapped(_ sender: UIButton) {
// 1. Проверяем, что текст не nil и не пустой
guard let text = textField.text, !text.isEmpty else {
// Можно показать alert, что нечего копировать
print("Текст пуст")
return
}
// 2. Копируем в буфер обмена
UIPasteboard.general.string = text
// 3. (Опционально) Показываем пользователю обратную связь
// Например, меняем текст кнопки на "Скопировано!" на секунду
let originalTitle = copyButton.title(for: .normal)
copyButton.setTitle("Скопировано!", for: .normal)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.copyButton.setTitle(originalTitle, for: .normal)
}
}
}
Почему ваш код мог не работать?
- Проверка на nil: Если
textField.textравенnil, присвоениеUIPasteboard.general.string = nilпросто очистит буфер обмена. Всегда проверяйте значение через guard или if let. - Соединение IBOutlet: Убедитесь, что
textFieldиcopyButtonправильно подключены в Storyboard или XIB. Если соединение отсутствует, код не выполнится. - Вызов на главном потоке: Все UI-операции должны выполняться на главном потоке. Ваш
@IBActionобычно вызывается оттуда, но если вы вызываете копирование из фоновой очереди (например, после URLSession), оберните вDispatchQueue.main.async.
Дополнительные возможности UIPasteboard
Вы можете копировать не только строки, но и другие типы данных:
// Копирование изображения
UIPasteboard.general.image = UIImage(named: "example")
// Копирование URL
UIPasteboard.general.url = URL(string: "https://example.com")
// Копирование нескольких объектов (например, для богатого текста)
let items: [[String: Any]] = [
[UIPasteboard.typeAutomatic: "Текст",
UIPasteboard.typeAutomatic: UIImage(named: "icon") as Any]
]
UIPasteboard.general.items = items
Важное замечание о конфиденциальности (iOS 14+)
Начиная с iOS 14, система показывает уведомление, когда приложение читает данные из буфера обмена. Это не влияет на запись (копирование) — вы по-прежнему можете писать в UIPasteboard без каких-либо уведомлений. Однако, если ваше приложение читает буфер обмена (например, UIPasteboard.general.string), пользователь увидит предупреждение. Старайтесь читать буфер только в ответ на явное действие пользователя (например, нажатие кнопки "Вставить").
Совет для начинающих
Для большей надёжности и читаемости кода рекомендую вынести логику копирования в отдельный метод:
func copyToClipboard(_ text: String) {
guard !text.isEmpty else { return }
UIPasteboard.general.string = text
// Дополнительно: вибрация или анимация для тактильного отклика
let feedbackGenerator = UIImpactFeedbackGenerator(style: .medium)
feedbackGenerator.prepare()
feedbackGenerator.impactOccurred()
}
Таким образом, ваш код станет более модульным и его легко будет переиспользовать в других частях приложения.
<<Альтернативный подход: использование UIPasteboard с типом данных
Вместо установки свойства string напрямую, можно использовать метод setValue(_:forPasteboardType:). Это даёт больше контроля над форматом данных и может быть полезно, если вы работаете с разными типами контента (например, HTML или RTF).
@IBAction func copyWithType(_ sender: UIButton) {
guard let text = textField.text else { return }
let pasteboard = UIPasteboard.general
pasteboard.setValue(text, forPasteboardType: "public.plain-text")
}
Когда это может пригодиться? Если вы копируете форматированный текст (например, из UILabel с атрибутами), вы можете указать тип "public.html" или "public.rtf". Это позволит другим приложениям (например, Pages или Mail) правильно распознать форматирование.
Ещё один вариант — использование обёртки Pasteboard для SwiftUI. Если вы пишете на SwiftUI (iOS 14+), можно использовать модификатор .onTapGesture и встроенный UIPasteboard:
import SwiftUI
struct ContentView: View {
@State private var text = "Привет, мир!"
var body: some View {
Text(text)
.onTapGesture {
UIPasteboard.general.string = text
}
}
}
Этот подход более лаконичный, но требует импорта UIKit в SwiftUI-проекте (что обычно делается автоматически). Помните, что в SwiftUI нет прямого аналога UIPasteboard, поэтому приходится использовать UIKit.