好的,看起來像我犯了幾個小錯誤,導致我認爲它不工作。但是,最終我能夠使其工作。所以,如果你正面臨着同樣的任務,這裏是斯威夫特3的解決方案:
(1)你必須實現服務方法:
import Cocoa
class ServiceProvider: NSObject {
let errorMessage = NSString(string: "Could not find the text for parsing.")
func service(_ pasteboard: NSPasteboard, userData: String?, error: AutoreleasingUnsafeMutablePointer<NSString>) {
guard let str = pasteboard.string(forType: NSStringPboardType) else {
error.pointee = errorMessage
return
}
let alert = NSAlert()
alert.messageText = "Hello \(str)"
alert.informativeText = "Welcome in the service"
alert.addButton(withTitle: "OK")
alert.runModal()
}
}
,我之前不知道這裏重要的是,提供服務的對象必須繼承NSObject(它也可以是ViewController或任何其他NSObject子類)。 Services API使用選擇器來調用它,而選擇器技術僅適用於NSObject。
此外,service
方法有這樣的聲明:它需要3個參數,第一個是NSPasteboard
(你可以使用Pasteboard
,但不提供string
方法)並沒有標註,第二個是可選的String
標記userData
,第三個是AutoreleasingUnsafeMutablePointer<NSString>
標註爲error
。按照這個來獲得最佳的安全性,同時仍然可以正常工作。否則,服務API將無法找到並調用它。你可以使用UnsafeRawPointers
作爲它的所有參數,但你不會因此得到任何東西。
(2)在應用程序委託(或文檔中說,你可以在任何地方,但我在這裏做的話)你註冊服務提供商:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
NSApplication.shared().servicesProvider = ServiceProvider()
NSUpdateDynamicServices()
}
}
它似乎還在努力沒有NSUpdateDynamicServices
呼叫,但我想最好是安全而不是抱歉 - 它應該刷新系統中的服務,以便您不必註銷並登錄用戶以獲取當前的服務版本。
(3)最後,你必須配置的Info.plist宣傳您的服務方法:
<key>NSServices</key>
<array>
<dict>
<key>NSMessage</key>
<string>service</string>
<key>NSPortName</key>
<string>serviceTest</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Test hello world</string>
</dict>
<key>NSRestricted</key>
<false/>
<key>NSRequiredContext</key>
<dict/>
<key>NSSendTypes</key>
<array>
<string>NSStringPboardType</string>
</array>
</dict>
</array>
這是Info.plist中的XML源 - 雖然蘋果推薦使用他們的編輯, Xcode 8.2我無法通過編輯器添加NSRequiredContext
密鑰 - 我必須將該文件作爲源代碼打開並手動添加。我會建議直接編輯XML源代碼。
你可以在Services Properties找到關於每個鍵的含義的文檔,但是我想提一些關鍵點。首先,你需要NSRequiredContext
鍵 - 他們在文檔中提到它,但編輯器不支持它 - 直接編輯XML並添加它甚至是空的(就像我這樣做)。其次,如果您使用的是NSSendTypes
或NSReturnTypes
,並且您想要使用字符串,請使用NSStringPboardType
,即使其documentation表示它已被棄用,應該由NSPasteboardTypeString
替代 - 後者將不起作用。最後,NSMessage
鍵與service
值是服務方法的名稱。所以,我的服務提供者對象聲明如下方法:
func service(_ pasteboard: NSPasteboard, userData: String?, error: AutoreleasingUnsafeMutablePointer<NSString>)
我在NSMessage
使用service
值。如果您想更改它(例如,您需要多個服務方法),請不要忘記這兩者必須匹配(Info.plist配置中的值和服務方法的名稱)。
(4)在這種狀態下它應該工作。有一件事我想提一提,可能會幫助你進行調試。測試使用在年底documentation提到的方法是通過運行:
/Applications/TextEdit.app/Contents/MacOS/TextEdit -NSDebugServices com.mycompany.myapp
從終端運行此應報告使用提供捆綁的任何服務是否被註冊,並且還是否將提交 - 例如,在我的情況下,問題是我沒有提供強制性的NSRequiredContext
。使用這種方法對其進行測試後,我能夠識別該服務已安裝,問題在於服務API假定它應該被過濾掉。經過一些實驗和谷歌搜索,我通過添加空NSRequiredContext
來解決它。
在每次更改服務之後,我建議退出TextEdit並重新運行它,它似乎保留對舊的服務提供者對象的引用(或類似的東西,如果我沒有重新啓動,則沒有通過TextEdit註冊更改它)。