【问题标题】:Couple service related "bugs"与服务相关的“错误”
【发布时间】:2013-11-10 20:41:52
【问题描述】:

我编写了一个可以作为服务调用的应用程序(通过右键单击 Finder 中的文件并选择使用我的应用程序打开它),但是这样做会产生一些不需要的副作用。

服务目标方法示例:

- (void)doSomething:(NSPasteboard *)pboard userData:(NSString *)userData error:(NSString **)error {
    NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
    NSLog(@"Selected file(s): %@", files);
    [self.anotherWindow makeKeyAndOrderFront:self];
}

1) 当应用程序以这种方式启动时(即使已经在调试模式下打开),我似乎无法从 doSomething 函数访问其他窗口/控件。例如,上面显示“anotherWindow”的尝试不会产生错误,但不会“做”任何事情。根据堆栈跟踪,当从 -doSomething 检查时,所有 gui 组件的值都为 0x0000000000000000 - 但应用程序已显示并且功能齐全。只有 -doSomething 我无法联系到他们。从 -doSomething 与 -applicationDidFinishLaunching 检查时,“self”也有不同的值。我不确定 -doSomething 如何或为什么使用未初始化的组件获取不同的 self/AppDelegate。 似乎已由 [NSApp setServicesProvider:self] 修复;

2) 我不清楚系统如何决定在调用服务时启动应用程序的哪个副本,但它通常不会选择我想要的那个。我在 /Debug 中有一个副本,在 /Release 中有一个副本,在我的桌面上有一个副本......如果我删除一个,它会打开另一个文件(某种回退链?)。如何配置服务(在代码中或通过 .plist)以打开此应用程序的特定版本/位置?但这是一台开发机器。如果我发布一个安装到 /Applications 的分发包,我真的需要担心这个吗?

【问题讨论】:

  • 我将 NSAlerts 添加到 -doSomething 和 -applicationDidFinishLaunching。 -applicationDidFinishLaunching 中的那个首先被触发,我看到了主应用程序窗口(self.mainWindow)。然后 -doSomething 中的那个弹出,并打印 self.mainWindow 是(null)。尽管我可以看到它并与之互动。 -doSomething 是否不在同一个实例中运行?

标签: objective-c macos cocoa xcode4.6


【解决方案1】:

1) 仔细检查您的 XIB 以确保您已正确连接所有内容,然后尝试启动应用程序并在上面的 NSLog 处设置断点并验证 self.anotherWindow 是否指向您想要的。如果由于某种原因断点没有触发,请尝试添加:

NSLog( @"Window: %@", self.anotherWindow);

确保一切都已初始化和连接

2) 系统使用Launch Services 来确定要启动哪个版本的应用程序。通常它是最近添加到系统中的版本(这将导致 Launch Services 数据库被修改),但根据您的系统配置方式,它可能不是您期望的版本。

您可以使用以下方式手动查询和修改启动服务数据库:

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister

(是的,真的很长的路)。如果您使用-dump 选项,它将为您提供系统中的所有数据(通过管道输入文件并搜索它以更好地了解正在发生的事情)。如果您搜索捆绑包 ID,您将看到该应用程序的所有条目。通常,最近获胜,但您可以强制重新加载(说明如下)。

如果您只想根据特定二进制文件强制重新加载,请使用 -f 标志和应用程序路径:

..../lsregister -f /Applications/Foo.app

您还可以使用-u 显式取消注册。

希望这能让您了解这里发生了什么。

【讨论】:

  • 如果我将此应用分发给其他人,确保正确注册服务的最佳方法是什么?我目前正在代码中执行 [NSApp setServicesProvider:appDelegate] 和 NSUpdateDynamicServices(),但它显​​然没有将操作系统定向到最近执行这些命令的应用程序版本。
  • NSLog(@"Window: %@", self.anotherWindow);打印窗口:(空)。 NSLog(@"%@", self) 从 -doSomething 打印“”,从 -applicationDidFinishLaunching 打印“”。不同的自我实例?
  • @Eric 关于确保服务正确注册的问题,一次只能在用户的机器上安装一个具有特定捆绑 ID 的应用程序。安装 App 后,操作系统会读取 Info.plist 并根据需要注册任何服务(当然,您也需要处理 Services 配置)
  • @Eric 根据您的NSLogs,听起来您的应用程序中有单独的 AppDelegate 实例,或者是单独的进程,或者您正在创建第二个委托。在您的 AppDelegate 创建代码中添加断点并检查堆栈跟踪和两个调用中的每一个的进程信息,以查看它们的来源。
  • 我添加了断点,并且在线程1下的堆栈跟踪中,0 - [AppDelegate..],self =(AppDelegate *),当从-doSomething检查时,它表明所有gui组件都有值0x00000000000000000,我认为这不是一个好兆头。在任何一种情况下,它们似乎都采用基本相同的 init 路线。 start->main->NSApplicationMain->.. 接下来的 2 个步骤略有不同。但我本身从未编写过任何初始化代码,也没有在任何地方明确创建第二个委托。基本上在xcode中新建了一个项目,在applicationDidFinishLaunching阶段就开始写代码了。
猜你喜欢
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
  • 2017-07-25
  • 2012-03-11
  • 2012-11-13
  • 2016-12-23
  • 1970-01-01
相关资源
最近更新 更多