在Finder上下文中建立服务

qwe*_*_so 2 service finder contextmenu swift

我正在尝试使用此类向Finder的上下文菜单添加服务:

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()
  }
}
Run Code Online (Sandbox Code Playgroud)

该服务在info.plist中公布如下:

<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>
Run Code Online (Sandbox Code Playgroud)

最后,我在系统偏好设置/键盘/快捷方式中打开了该服务.所以我看到了服务并且可以调用它.但是我在打电话时得到的只是

找不到选择器handleServices的服务提供者:userData:error:或handleServices :: for service handleServices

Mar*_*n R 5

您的代码中存在两个问题:

  • Objective-C消息被发送到服务提供者,因此Swift方法必须是"Objective-C兼容".这可以通过子类化NSObject或通过使用@objc属性标记方法来实现 .

  • 服务处理程序方法具有签名

    - (void)handleServices:(NSPasteboard *)pboard
                  userData:(NSString *)userData
                     error:(NSString **)error
    
    Run Code Online (Sandbox Code Playgroud)

    它映射到Swift as

    func handleServices(pboard: NSPasteboard!,
                      userData: String!,
                         error: AutoreleasingUnsafeMutablePointer<NSString?>)
    
    Run Code Online (Sandbox Code Playgroud)

所以这将是一个正确的版本(在我的测试中工作):

public class Service {

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

        // ...
    }

    init() {
        NSApp.servicesProvider = self
        NSUpdateDynamicServices()
    }
}
Run Code Online (Sandbox Code Playgroud)

还有一些评论:

if (pboard.types?.contains(NSFilenamesPboardType) != nil) { ... }
Run Code Online (Sandbox Code Playgroud)

是"可选链接"并检查是否contains()可以调用该方法pboard.types,换句话说它只检查是否pboard.types != nil.你可能想要的是检查是否pboard.types != nil contains()方法返回true.这可以通过"nil-coalescing operator"来实现??:

if (pboard.types?.contains(NSFilenamesPboardType) ?? false) { ... }
Run Code Online (Sandbox Code Playgroud)

下一个,

pboard.propertyListForType(NSFilenamesPboardType)
Run Code Online (Sandbox Code Playgroud)

记录为返回一个可选的NSStrings 数组,因此你可以解包并将其转换为String数组

if let fileArray = pboard.propertyListForType(NSFilenamesPboardType) as? [String] { ... }
Run Code Online (Sandbox Code Playgroud)

最后,将完成分配错误字符串(对调用者提供的指针)

if (error != nil) {
    error.memory = "My error description"
}
Run Code Online (Sandbox Code Playgroud)