Establish a service in Finder context

心已入冬 提交于 2019-12-22 14:38:48

问题


I'm trying to add a service to the Finder's context menu using this class:

public class Service {
  public func handleServices(pboard:NSPasteboard, userData:String, error:UnsafeMutableBufferPointer<String>) {  // not sure about the correct parameters
    if (pboard.types?.contains(NSFilenamesPboardType) != nil) {
      let fileArray = pboard.propertyListForType(NSFilenamesPboardType)
      print(fileArray)
    }
  }

  init () {
    NSApp.servicesProvider = self
    NSUpdateDynamicServices()
  }
}

The service is announced in info.plist as follows:

<key>NSServices</key>
<array>
    <dict>
        <key>NSMenuItem</key>
        <dict>
            <key>default</key>
            <string>Service Handling Demo</string>
        </dict>
        <key>NSMessage</key>
        <string>handleServices</string>
        <key>NSPortName</key>
        <string>services</string>
        <key>NSSendTypes</key>
        <array>
            <string>NSFilenamesPboardType</string>
        </array>
    </dict>
</array>

Finally I have turned on the service in System Preferences/Keyboard/Shortcuts. So I see the service and can call it. But all I get when calling it is

Cannot find service provider for selector handleServices:userData:error: or handleServices:: for service handleServices


回答1:


There are two problems in your code:

  • Objective-C messages are sent to the service provider, therefore the Swift method must be "Objective-C compatible". This can be achieved by subclassing NSObject, or by marking the method with the @objc attribute.

  • The service handler method has the signature

    - (void)handleServices:(NSPasteboard *)pboard
                  userData:(NSString *)userData
                     error:(NSString **)error
    

    which is mapped to Swift as

    func handleServices(pboard: NSPasteboard!,
                      userData: String!,
                         error: AutoreleasingUnsafeMutablePointer<NSString?>)
    

So this would be a correct version (which worked in my test):

public class Service {

    @objc public func handleServices(pboard: NSPasteboard!,
        userData: String!, error: AutoreleasingUnsafeMutablePointer<NSString?>) {

        // ...
    }

    init() {
        NSApp.servicesProvider = self
        NSUpdateDynamicServices()
    }
}

Some more remarks:

if (pboard.types?.contains(NSFilenamesPboardType) != nil) { ... }

is "optional chaining" and checks if the contains() method could be called on pboard.types, in other words it checks only if pboard.types != nil. What you probably want is to check if pboard.types != nil and the contains() method returns true. This can be achieved with the "nil-coalescing operator" ??:

if (pboard.types?.contains(NSFilenamesPboardType) ?? false) { ... }

Next,

pboard.propertyListForType(NSFilenamesPboardType)

is documented to return an optional array of NSStrings, so you could unwrap and convert that to a String array with

if let fileArray = pboard.propertyListForType(NSFilenamesPboardType) as? [String] { ... }

Finally, assigning an error string (to the pointer provided by the caller) would be done with

if (error != nil) {
    error.memory = "My error description"
}



回答2:


Received same error (Swift 3.1). Tried all ways in this topic but nothing helped. Found a solution here

Changed code from this

@objc public func handleServices(pboard: NSPasteboard!,
    userData: String!, error: AutoreleasingUnsafeMutablePointer<NSString?>) 

to this

@objc public func handleServices(_ pboard: NSPasteboard,
 userData: String, error:AutoreleasingUnsafeMutablePointer<NSString>) 

and it works.




回答3:


Try creating aliases for variables in your method like so.

public func handleServices(pboard:NSPasteboard, userData userData:String, error error:UnsafeMutableBufferPointer<String>)


来源:https://stackoverflow.com/questions/31404026/establish-a-service-in-finder-context

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!