I'm a beginner with Swift, and I'm trying to figure out how can I read what has been copied to the clipboard On macOS (Swift 3)? I've searched a lot but can't seem to find anything that works.
A few of the things I've tried from online:
var pasteboardItems: [NSPasteboardItem]? { get }
print("\(pasteboardItems)")
and
let pb = NSPasteboard.general()
pb.string(forType: NSPasteboardTypeString)
print("\(pb)")
and
let pasteboard = UIPasteboard.general
if let string = pasteboard.string {
// text was found and placed in the "string" constant
}
and lastly
func paste(sender: AnyObject?) {
let pasteboard = NSPasteboard.generalPasteboard()
if let nofElements = pasteboard.pasteboardItems?.count {
if nofElements > 0 {
// Assume they are strings
var strArr: Array<String> = []
for element in pasteboard.pasteboardItems! {
if let str = element.stringForType("public.utf8-plain-text") {
strArr.append(str)
}
}
// Exit if no string was read
if strArr.count == 0 { return }
// Perform the paste operation
dataSource.cmdPaste(strArr)
}
}
}
Works for Swift 3 and Swift 4
// Set string to clipboard
let pasteboard = NSPasteboard.general
pasteboard.declareTypes([NSPasteboard.PasteboardType.string], owner: nil)
pasteboard.setString("Good Morning", forType: NSPasteboard.PasteboardType.string)
var clipboardItems: [String] = []
for element in pasteboard.pasteboardItems! {
if let str = element.string(forType: NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text")) {
clipboardItems.append(str)
}
}
// Access the item in the clipboard
let firstClipboardItem = clipboardItems[0] // Good Morning
Another Swift 4 Solution
// Write to pasteboard
let pasteboard = NSPasteboard.general
pasteboard.declareTypes([NSPasteboard.PasteboardType.string], owner: nil)
pasteboard.setString("Good Morning", forType: NSPasteboard.PasteboardType.string)
// Read from pasteboard
let read = pasteboard.pasteboardItems?.first?.string(forType: .string)
Times have changed. In Swift 3+ you would do it like this: (if you are only interested in strings)
func clipboardContent() -> String?
{
return NSPasteboard.general.pasteboardItems?.first?.string(forType: .string)
}
Another solution.
class ViewController : NSViewController {
#IBAction func pasteMenuItemAction(_ sender: NSMenuItem) {
let p = NSPasteboard.general
let x = p.readObjects(forClasses: [NSString.self], options: nil)
let s = x as! [NSString]
if 0 < s.count {
print(s[0])
}
}
}
That func pasteMenuItemAction() is bound to an Edit > Paste menu item.
I use writeObjects() for Edit > Copy. So it is natural for me to use its counterpart readObjects() here.
Confirmed with Xcode 9.2, Swift 4
Added:
One of the solutions for Edit > Copy:
#IBAction func copyMenuItemAction(_ sender: NSMenuItem) {
let t = "Hello!"
let p = NSPasteboard.general
p.clearContents()
p.writeObjects([t as NSPasteboardWriting])
}
That func copyMenuItemAction() is bound to an Edit > Copy menu item.
Easier ✅ Swift 4:
#IBAction func pasteAction(_ sender: Any) {
guard let stringToPaste: String = UIPasteboard.general.items.last?.first?.value as? String else { return }
MYTEXTVIEW.text = stringToPaste
}
Related
This question already has answers here:
UIDocumentPickerViewController is not working when testing with my iPad but fine with simulators
(2 answers)
Closed 12 months ago.
Update: This code works in the simulator, but not on my device. Obviously, I'm needing it to work on both.
I've followed the tutorials, yet I cannot seem to get this feature to work. When the user selects the barButtonItem, DocumentPicker opens allowing the user to select a .txt file. I then take the URL to the selected file and attempt to return a string from it; however, I'm getting the following error: "The file “Test.txt” couldn’t be opened because you don’t have permission to view it." What am I missing? Did I fail to ask for permission somewhere? I've tried cleaning the build folder - didn't work.
#IBAction func importFileBtnTapped(_ sender: Any) {
selectFiles()
}
func selectFiles() {
let types = UTType.types(tag: "txt",
tagClass: UTTagClass.filenameExtension,
conformingTo: nil)
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: types)
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let myURL = urls.first else {
let alert = SCLAlertView()
alert.showError("ERROR", subTitle: "Unable to retrieve document.")
return
}
let text = createStringFromSelectedFile(fileURL: myURL)
if text == "error" {
print("ERROR creating a string from the selected file.")
return
}
let separatedStrings = decipherString(text: text)
if separatedStrings.first == "error" {
print("ERROR deciphering the string in ClaimInfoViewController")
return
}
for string in separatedStrings {
print("\(string)")
}
print("import result: \(myURL)")
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
func createStringFromSelectedFile(fileURL: URL) -> String {
var text = String()
do {
text = try String(contentsOf: fileURL)
}
catch {
print("ERROR in the createStringFromSelectedFile function in ClaimInfoViewController")
print("The error: \(error.localizedDescription)")
let alert = SCLAlertView()
alert.showError("ERROR", subTitle: "Unable to read the file. Please try again.")
return "error"
}
return text
}
func decipherString(text: String) -> [String]{
let newText = text
let startIndexes = ["<Claim#",
"<File#",
"<DateOfLoss:"
]
var claimNumber = String()
var fileNumber = String()
var dateOfLoss = String()
for indexValue in startIndexes {
guard let index = newText.firstIndex(of: ">") else { return ["error"] }
let newString = String(newText[..<index])
if indexValue == "<Claim#" {
claimNumber = newString
}
else if indexValue == "<File#" {
fileNumber = newString
}
else if indexValue == "<DateOfLoss:" {
dateOfLoss = newString
}
}
let finalText = [claimNumber, fileNumber, dateOfLoss]
return finalText
}
Thanks to matt, who commented above, I was able to find out that it's a security issue. Adding this simple code resolved the issue:
let shouldStopAccessing = pickedFolderURL.startAccessingSecurityScopedResource()
defer {
if shouldStopAccessing {
pickedFolderURL.stopAccessingSecurityScopedResource()
}
}
I added it right before this line of code that can be seen above:
let text = createStringFromSelectedFile(fileURL: myURL)
I got this code from here: StackOverflow Post
So i'm working a an app that can patch words that are broken.
Lets take:
mny people say there is a error in this sentence
With swift here we can us UITextChecker and get a wonderful result of what the word mny could actually be... However, i actually get a couple of choices, one of which is many and among the other you have money so obviously money wouldn't fit in very well in this sentence. Are there any way to check if the sentence itself is logical?
Consider that this still needs to be improved. I updated this swift 3 solution to Swift 5. Worth to mention that it was originally inspired by this python tutorial
Create a new iOS project, add there a text file named bigtext.txt which will contain this text. This will be our "learning" dictionary.
Then in ViewController:
import UIKit
import NaturalLanguage
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let inputString = "mny people say there is a error in this sentence"
var newString = inputString
// Read a text file and "study" the model
guard let path = Bundle.main.path(forResource: "bigtext", ofType: "txt") else {
print("Path not available")
return
}
let checker = SpellChecker(contentsOfFile: path)
// better to use this to iterate between words in a sentence
let tokenizer = NLTokenizer(unit: .word)
tokenizer.string = inputString
tokenizer.enumerateTokens(in: inputString.startIndex..<inputString.endIndex) { tokenRange, _ in
let word = String(inputString[tokenRange])
let checked = checker?.correct(word: word)
let candidates = checker?.candidates(word: word)
if word == checked {
print("\(word) unchanged")
} else {
if let checked = checked {
newString.replaceSubrange(tokenRange, with: checked)
}
print("Correct:\t\(word) -> \(String(describing: checked))")
print("Candidates:\t\(word) -> \(String(describing: candidates))")
}
return true
}
print("Result: \(newString)")
}
}
func edits(word: String) -> Set<String> {
if word.isEmpty { return [] }
let splits = word.indices.map {
(word[word.startIndex..<$0], word[$0..<word.endIndex])
}
let deletes = splits.map { $0.0 + String($0.1.dropFirst()) }
let transposes: [String] = splits.map { left, right in
if let fst = right.first {
let drop1 = String(right.dropFirst())
if let snd = drop1.first {
let drop2 = String(drop1.dropFirst())
return "\(left)\(snd)\(fst)\(drop2)"
}
}
return ""
}.filter { !$0.isEmpty }
let alphabet = "abcdefghijklmnopqrstuvwxyz"
let replaces = splits.flatMap { left, right in
alphabet.map { "\(left)\($0)\(String(right.dropFirst()))" }
}
let inserts = splits.flatMap { left, right in
alphabet.map { "\(left)\($0)\(right)" }
}
let setString = [String(deletes.first!)] + transposes + replaces + inserts
return Set(setString)
}
struct SpellChecker {
var knownWords: [String:Int] = [:]
mutating func train(word: String) {
if let idx = knownWords[word] {
knownWords[word] = idx + 1
}
else {
knownWords[word] = 1
}
}
init?(contentsOfFile file: String) {
do {
let text = try String(contentsOfFile: file, encoding: .utf8).lowercased()
let words = text.unicodeScalars.split(whereSeparator: { !("a"..."z").contains($0) }).map { String($0) }
for word in words { self.train(word: word) }
}
catch {
return nil
}
}
func knownEdits2(word: String) -> Set<String>? {
var known_edits: Set<String> = []
for edit in edits(word: word) {
if let k = known(words: edits(word: edit)) {
known_edits.formUnion(k)
}
}
return known_edits.isEmpty ? nil : known_edits
}
func known<S: Sequence>(words: S) -> Set<String>? where S.Iterator.Element == String {
let s = Set(words.filter { self.knownWords.index(forKey: $0) != nil })
return s.isEmpty ? nil : s
}
func candidates(word: String) -> Set<String> {
guard let result = known(words: [word]) ?? known(words: edits(word: word)) ?? knownEdits2(word: word) else {
return Set<String>()
}
return result
}
func correct(word: String) -> String {
return candidates(word: word).reduce(word) {
(knownWords[$0] ?? 1) < (knownWords[$1] ?? 1) ? $1 : $0
}
}
}
Will output you:
Correct: mny -> Optional("may")
Candidates: mny -> Optional(Set(["any", "ny", "may", "many"]))
people unchanged
say unchanged
there unchanged
is unchanged
a unchanged
error unchanged
in unchanged
this unchanged
sentence unchanged
Result: may people say there is a error in this sentence
Please, consider that we took first correction candidate.
Need first to clarify ourselves the word order and understand the sentence context.
I'm trying to output result in text field in Swift 3, but when the button is pressed nothing happens, doesn't even print in the console. It should be somewhere in the last 3 lines of code I guess. I can't figure out what I'm doing wrong, so your help is much appreciated! I'm also new to Swift, so it may be something obvious to you, but dead end for me.
And this is my code:
#IBAction func encrypt(sender: AnyObject?) {
let text = encryptText.text
let key = pkey.text
func encrypt(text: String) -> (text: String, key: [Int]) {
let text = text.lowercased()
let key = self.key(count: text.characters.count)
let map = self.map()
var output = String()
for (index, character) in text.characters.enumerated() {
if character == " " {
output.append(character)
}
else {
if let letterIndex = map.forward[String(character)] {
let keyIndex = key[index]
let outputIndex = (letterIndex + keyIndex + map.lastCharacterIndex) % map.lastCharacterIndex
if let outputCharacter = map.reversed[outputIndex] {
output.append(outputCharacter)
}
}
}
}
print(text)
outputText.text = output
return (text: output.uppercased(), key: key)
}
}
You have a function (encrypt) nested in another function (the #IBAction also called encrypt), but you are never calling the nested function. Try something like this:
#IBAction func encrypt(sender: AnyObject?) {
func encrypt(text: String) -> (text: String, key: [Int]) {
let text = text.lowercased()
let key = self.key(count: text.characters.count)
let map = self.map()
var output = String()
for (index, character) in text.characters.enumerated() {
if character == " " {
output.append(character)
}
else {
if let letterIndex = map.forward[String(character)] {
let keyIndex = key[index]
let outputIndex = (letterIndex + keyIndex + map.lastCharacterIndex) % map.lastCharacterIndex
if let outputCharacter = map.reversed[outputIndex] {
output.append(outputCharacter)
}
}
}
}
return (text: output.uppercased(), key: key)
}
let text = encryptText.text
let key = pkey.text
// call the encrypt function
let (resultText, resultKey) = encrypt(text: text)
// put the result in the text view
outputText.text = resultText
}
It's also a little difficult to determine exactly what you are doing because you declare so many variables with the same names (text, key, encrypt, etc). Choosing slight variations of those names can improve the readability of your code.
NSKeyedArchiver.archiveRootObject(<#rootObject: AnyObject#>, toFile: <#String#>)
Only returns true the first time. Every next time I call it, the method returns false.
I read some SO, some posts said that I can't rewrite data this way. However, I tried :
NSFileManager.defaultManager().removeItemAtPath(path, error: nil)
and it still didn't help.
What I did:
Checked all my model files for the NSCoding protocol
Checked all my required init(coder aDecoder: NSCoder) and func encodeWithCoder(aCoder: NSCoder)
I am missing something, since I have done this in my last app and it worked fla`
import Foundation
private let ON_DISK_DATA_DICTIONARY = "savedDataPathsOnDisk"
private let _WBMAccessDataOnDiskMShared = WBMAccessDataOnDiskM()
private var dataDirectories:NSArray! = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
private var dataDirectoryURL:NSURL! = NSURL(fileURLWithPath: dataDirectories.objectAtIndex(0) as! String, isDirectory: true)
private var dataDirectoryPath:String! = dataDirectoryURL.path!
let FILE_FORMAT = ".archive"
class WBMAccessDataOnDiskM: NSObject
{
class var sharedData: WBMAccessDataOnDiskM
{
return _WBMAccessDataOnDiskMShared
}
private var dataAndPathDictionary = [String:String]()
func getDataAndPathDictionary() -> [String:String]
{
return self.dataAndPathDictionary
}
func addDataAndPathToDictionary(data:String ,path:String)
{
if !checkIfDataAllreadyExists(data)
{
let fullPath = createFullDataPath(path)
dataAndPathDictionary[data] = fullPath
NSUserDefaults.standardUserDefaults().setObject(dataAndPathDictionary, forKey: ON_DISK_DATA_DICTIONARY)
}
}
func checkIfDataIsAvailable(dataPathComponent:String) -> (Bool,String)
{
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
var dataPath = paths.stringByAppendingPathComponent(dataPathComponent)
var checkValidation = NSFileManager.defaultManager()
println(dataPathComponent)
if (checkValidation.fileExistsAtPath(dataPath))
{
return (true,dataPath)
}
else
{
return (false,"")
}
}
func checkForDataOnDisk() -> Bool
{
let dataDict = NSUserDefaults.standardUserDefaults().objectForKey(ON_DISK_DATA_DICTIONARY) as? [String:String]
if dataDict == nil
{
return false
}
else
{
dataAndPathDictionary = dataDict!
return true
}
}
private func checkIfDataAllreadyExists(data:String) -> Bool
{
let keys = self.dataAndPathDictionary.keys.array
if contains(keys, data)
{
return true
}
return false
}
private func createFullDataPath(path:String) -> String
{
var fullPathURL = dataDirectoryURL.URLByAppendingPathComponent(path + FILE_FORMAT)
return fullPathURL.path!
}
func saveDataArray(data:[AnyObject], path:String)
{
NSFileManager.defaultManager().removeItemAtPath(path, error: nil)
if NSKeyedArchiver.archiveRootObject(data, toFile: path)
{
// SAVING
println(" Saving data ARRAY ")
}
else
{
println(" NOT saving data ARRAY ")
}
}
func saveDataObject(dataObject:AnyObject, path:String)
{
if NSKeyedArchiver.archiveRootObject(dataObject, toFile: path)
{
println(" Saving data OBJECT ")
}
else
{
println(" NOT saving data OBJECT ")
}
}
// dataFromDisk = NSKeyedUnarchiver.unarchiveObjectWithFile(pathForNews) as? [AnyObject]
func loadDataArray(path:String) -> [AnyObject]?
{
var dataArrayFromDisk: [AnyObject]?
dataArrayFromDisk = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? [AnyObject]
return dataArrayFromDisk
}
func loadDataObject(path:String) -> AnyObject?
{
var dataObjectFromDisk: AnyObject?
dataObjectFromDisk = NSKeyedUnarchiver.unarchiveObjectWithFile(path)
return dataObjectFromDisk
}
func getNewsDataLanguagePath() -> String
{
var currentOSLanguage = LOCALIZATION.currentOsLanguage
currentOSLanguage = currentOSLanguage.substringToIndex(2)
if currentOSLanguage == "de"
{
return ON_DISK_CONTENT_DE
}
else if currentOSLanguage == "en"
{
return ON_DISK_CONTENT_ENG
}
return ON_DISK_CONTENT_ENG
}
`
I am using Xcode 6.4 and Swift 1.2.
Any help & code correction is welcome.
Because of the code you put here does't contain the call of saveDataArray or saveDataObject so I judge that you have maintain the path of a archived object manually.This is where thing went wrong. The method of NSKeyedArchiver named archiveRootObject can automatically maintain the archiver file path.
In the Apple's doucumet
Archives an object graph rooted at a given object by encoding it into a data object then atomically writes the resulting data object to a file at a given path, and returns a Boolean value that indicates whether the operation was successful.
And there is another question in SO may help you.
I followed apple instructions in this good example: Persist Data
But I had the same problem you describe with my app for AppleTV. At the end I change .Documents directory for CacheDirectory and it's working well.
static let DocumentsDirectorio = NSFileManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first!
I am trying to currently display the album artwork for a locally stored .MP3 track in an ImageView. Does anyone know how to fetch this artwork in Swift in order to accomplish this?
I have found this solution (iOS AVFoundation: How do I fetch artwork from an mp3 file?) but the code is written in Objective C. I simply want to grab the image embedded in my MP3 and display it in my ImageView.
I've looked at the API documentation for the MPMediaItemArtwork and found an example that also accomplishes what I am trying to accomplish in Objective C as well here(http://www.codeitive.com/0zHjkUjUWX/not-able-to-get-the-uiimage-from-mpmediaitempropertyartwork.html) but cannot come up with a solution. My code is as follows:
import UIKit
import AVFoundation
import MediaPlayer
class ViewController: UIViewController {
let audioPath:NSURL! = NSBundle.mainBundle().URLForResource("SippinOnFire", withExtension: "mp3")
#IBOutlet var artistImage: UIImageView!
#IBOutlet var trackLabel: UILabel!
#IBOutlet var artistLabel: UILabel!
#IBOutlet var sliderValue: UISlider!
var player:AVAudioPlayer = AVAudioPlayer()
#IBAction func play(sender: AnyObject) {
let audioInfo = MPNowPlayingInfoCenter.defaultCenter()
println(audioInfo)
player.play()
//println("Playing \(audioPath)")
let playerItem = AVPlayerItem(URL: audioPath)
let metadataList = playerItem.asset.metadata as! [AVMetadataItem]
for item in metadataList {
if let stringValue = item.value {
println(item.commonKey)
if item.commonKey == "title" {
trackLabel.text = stringValue as? String
}
if item.commonKey == "artist" {
artistLabel.text = stringValue as? String
}
if item.commonKey == "artwork" {
if let audioImage = UIImage(data: item.value as! NSData) {
let audioArtwork = MPMediaItemArtwork(image: audioImage)
println(audioImage.description)
}
}
}
}
}
#IBAction func pause(sender: AnyObject) {
player.pause()
}
#IBAction func stop(sender: AnyObject) {
player.stop()
player.currentTime = 0;
}
#IBAction func sliderChanged(sender: AnyObject) {
player.volume = sliderValue.value
}
override func viewDidLoad() {
super.viewDidLoad()
var error:NSError? = nil
player = AVAudioPlayer(contentsOfURL: audioPath!, error: &error)
player.volume = 0.5;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Here is a screen shot of my sample .mp3 file. As you can see there is indeed album artwork that is both visible in the "get info" section of Finder. I've also opened the .mp3 in my iTunes to make sure and have confirmed there is artwork in the "get info" section of it there as well as under the "artwork" tab.
However, when trying to use the commonKey to assign the image to my imageView I find that there is no commonKey for "artwork".
Thanks
Change your snippet of code into this (I already tested it):
I added println lines commented in places of interest, Feel free to uncomment in order to see what is happening.
for item in metadataList {
if item.commonKey == nil{
continue
}
if let key = item.commonKey, let value = item.value {
//println(key)
//println(value)
if key == "title" {
trackLabel.text = value as? String
}
if key == "artist" {
artistLabel.text = value as? String
}
if key == "artwork" {
if let audioImage = UIImage(data: value as! NSData) {
//println(audioImage.description)
artistImage.image = audioImage
}
}
}
}
UPDATE: A bit of clean up of this code
for item in metadataList {
guard let key = item.commonKey, let value = item.value else{
continue
}
switch key {
case "title" : trackLabel.text = value as? String
case "artist": artistLabel.text = value as? String
case "artwork" where value is NSData : artistImage.image = UIImage(data: value as! NSData)
default:
continue
}
}
UPDATE: For Swift 4
for item in metadataList {
guard let key = item.commonKey?.rawValue, let value = item.value else{
continue
}
switch key {
case "title" : trackLabel.text = value as? String
case "artist": artistLabel.text = value as? String
case "artwork" where value is Data : artistImage.image = UIImage(data: value as! Data)
default:
continue
}
}
edit/update Swift 4 or later:
import MediaPlayer
var nowPlayingInfo: [String: Any] = [:]
let playerItem = AVPlayerItem(url: url)
let metadataList = playerItem.asset.metadata
for item in metadataList {
switch item.commonKey {
case .commonKeyTitle?:
nowPlayingInfo[MPMediaItemPropertyTitle] = item.stringValue ?? ""
case .commonKeyType?:
nowPlayingInfo[MPMediaItemPropertyGenre] = item.stringValue ?? ""
case .commonKeyAlbumName?:
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = item.stringValue ?? ""
case .commonKeyArtist?:
nowPlayingInfo[MPMediaItemPropertyArtist] = item.stringValue ?? ""
case .commonKeyArtwork?:
if let data = item.dataValue,
let image = UIImage(data: data) {
nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { _ in image }
}
case .none: break
default: break
}
}
let audioInfo = MPNowPlayingInfoCenter.default()
audioInfo.nowPlayingInfo = nowPlayingInfo
Note: You will have to invoke beginReceivingRemoteControlEvents() otherwise it will not work on the actual device. You will also need to set your app Background Modes (Audio and AirPlay) and set your AVAudioSession category to AVAudioSessionCategoryPlayback and set it active:
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
Try this:
It appears that sometimes iOS 8 returns nil at first attempt of obtaining this info:
if let audioCenter = MPNowPlayingInfoCenter.defaultCenter(){
if let audioInfo = audioCenter.nowPlayingInfo{
if let artwork = audioInfo[MPMediaItemPropertyArtwork] as? MPMediaItemArtwork
{
var image: UIImage? = artwork.imageWithSize(artwork.bounds.size)
if image == nil {
image = artwork.imageWithSize(artwork.bounds.size);
}
if image != nil{
println("image loaded")
}
}
}
}