【问题标题】:Incorrect (but non-error-throwing) return value with a Scripting Bridge call to Finder under 10.6在 10.6 下使用 Scripting Bridge 调用 Finder 时返回值不正确(但不会引发错误)
【发布时间】:2011-03-31 23:43:36
【问题描述】:

我一直在 StackOverflow 和其他地方浏览大量与 Scripting Bridge 相关的线程,但似乎无法在弄清楚为什么 Cocoa 代码块对 Finder 进行 Scripting Bridge 调用没有任何进展在 10.6 下,longer 可以正常工作。 (类似版本的代码在 10.5 下似乎可以正常工作,我不知道是什么导致了行为变化。)

基本上,我正在尝试访问 Finder 窗口的一些显示选项。我有以下代码块作为我的测试用例。我将它指向一个 is 显示为图标的文件夹,当我运行代码时,没有任何错误块跳闸,但我总是在结束。

    // Set up the Scripting Bridge
    FinderApplication *finder = [SBApplication applicationWithBundleIdentifier:@"com.apple.finder"];

    // Get an HFS-style reference to a specified folder
    // (folderPath is an NSString * containing a POSIX-style path to a folder)
    NSURL *folderURL = [NSURL fileURLWithPath:folderPath];
    NSString *folderPathHFS = (NSString *)CFURLCopyFileSystemPath((CFURLRef)folderURL, kCFURLHFSPathStyle);

    // Get the Finder-native folder reference
    FinderFolder* folder = [[finder folders] objectAtLocation:folderPathHFS];
    if (folder == nil) {
        NSLog(@"folder error: %@", [[folder lastError] localizedDescription]);
        return;
    }

    // Get the Finder-native container window associated with the folder
    [folder openUsing:finder withProperties:nil];
    FinderFinderWindow *folderWindow = [[folder containerWindow] get];
    if (folderWindow == nil) {
        NSLog(@"folderWindow error: %@", [[folderWindow lastError] localizedDescription]);
        return;
    }

    // Retrieve the view preferences for the folder
    FinderIconViewOptions *ivo = [folderWindow iconViewOptions];
    if (ivo == nil) {
        NSLog(@"ivo error: %@", [[ivo lastError] localizedDescription]);
    }

    // Get the current icon size
    int iconSize = (int)[ivo iconSize];

    // Display the icon size in our label
    if (iconSize > 0) {
        NSLog(@"successfully retrieved icon size: %d", iconSize);
    } else {
        NSLog(@"couldn't retrieve icon size");
    }

此代码的纯 AppleScript 版本运行良好,即使指向同一个文件夹:

tell application "Finder"
        set aFolder to the folder "<HFS path to folder in question>"
        set aFolderWindow to the container window of aFolder
        set aIVO to the icon view options of aFolderWindow
        return the icon size of aIVO
end tell

我的直觉是某些东西在通过脚本桥时被奇怪地转换或转换,但我完全不知道要检查什么或在哪里查看。在从 Finder 检索对象并将 [SBObject *get] 调用标记到各种 SB 相关赋值语句的末尾时,我尝试打印出类名,但无济于事。

有什么想法吗?


更新

好的,所以我发现在哪里在上面的代码中生成了错误,尽管我不觉得我离解决问题更近了。事实证明,Scripting Bridge 的惰性评估掩盖了这个问题。如果在检索到 FinderWindow 的引用后,插入以下两行代码:

NSString *test = [folderWindow name]; NSLog(@"Return value == %@; error message == %@", test, [[folderWindow lastError] localizedDescription]);

然后,Scripting Bridge 尝试实际执行名称检索,但失败了,并返回一条更具建设性的错误消息:

Return value == (null); error message == The operation couldn’t be completed. (OSStatus error -1700.)

这太棒了(进步?!),但仍然没有让我更接近解决问题。该错误消息似乎表明某处存在 AEcoercion 问题,但我不确定如何继续解决它。生成的 Finder.h 文件(和 Finder 的 AppleScript 字典)都非常清楚我应该取回对 FinderWindow 对象的引用,并且打印出 folderWindow 对象似乎可以验证一切正常,直到name 电话。

【问题讨论】:

  • 我不确定这是否有用,但我也确定发生的任何问题都可能在[folderWindow iconViewOptions] 检索调用之前发生(即,这不仅仅是问题抓住IVO结构)。如果我在获得文件夹窗口的引用后尝试更简单的方法,例如 NSLog(@'Finder window id: %@", [folderWindow id]);,我会得到相同的无用(和不正确)零结果。

标签: objective-c cocoa macos applescript scripting-bridge


【解决方案1】:

看起来 -objectAtLocation: 期待的是 NSURL,而不是 HFS 样式的路径:

"讨论

这个方法是 objectAtIndex: 的泛化 没有“索引”的应用程序 只是一个整数。例如,查找器 可以使用NSURL 指定对象 对象作为位置。在 OSA 中,这是 被称为“绝对位置”的 概念的概括 Foundation 中的“索引”——它可能是一个 整数,但不一定是。一种 单个对象甚至可能有一个数字 不同的“绝对位置” 值取决于容器。”

我刚刚尝试了使用 NSURL 的代码,它运行良好。比如下面的代码

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    MDFinderApplication *finder = [SBApplication 
            applicationWithBundleIdentifier:@"com.apple.finder"];

    NSURL *URL = [NSURL fileURLWithPath:[@"~/Desktop" stringByStandardizingPath]];
    if (URL) {
         MDFinderFolder *folder = [[finder folders] objectAtLocation:URL];
         NSLog(@"folder == %@", folder);
    }
}

产生以下输出:

folder == <FinderFolder @0x482b00: FinderFolder 'furl'("file://localhost/Users/mdouma46/Desktop/") of application "Finder" (78829)>

(注意:我在创建 Finder.h 文件时使用了不同的参数(以防止混淆名称,如 FinderFinderWindow),所以我的类名会略有不同。

因此,只要将代码更改为以下内容,您的代码应该可以正常工作:

// Set up the Scripting Bridge
FinderApplication *finder = [SBApplication 
      applicationWithBundleIdentifier:@"com.apple.finder"];

// (folderPath is an NSString * containing a POSIX-style path to a folder)
NSURL *folderURL = [NSURL fileURLWithPath:folderPath];

// Get the Finder-native folder reference
FinderFolder* folder = [[finder folders] objectAtLocation:folderURL];
if (folder == nil) {
    NSLog(@"folder error: %@", [[folder lastError] localizedDescription]);
    return;
}

// Get the Finder-native container window associated with the folder
[folder reveal];
FinderFinderWindow *folderWindow = [folder containerWindow];
if (folderWindow == nil) {
    NSLog(@"folderWindow error: %@", [[folderWindow lastError] localizedDescription]);
    return;
}

// Retrieve the view preferences for the folder
// UPDATED: THE FOLLOWING WILL CAUSE AN "unrecognized selector":
FinderIconViewOptions *ivo = [folderWindow iconViewOptions];
if (ivo == nil) {
    NSLog(@"ivo error: %@", [[ivo lastError] localizedDescription]);
}

// Get the current icon size
int iconSize = (int)[ivo iconSize];

// Display the icon size in our label
if (iconSize > 0) {
    NSLog(@"successfully retrieved icon size: %d", iconSize);
} else {
    NSLog(@"couldn't retrieve icon size");
}

更新: 应该不需要您添加的-get 电话; get 是隐含的/可选的/多余的,就像在常规 AppleScript 中一样。

我在尝试获取 [folderWindow iconViewOptions] 时收到 unrecognized selector 错误消息:

-[SBObject iconViewOptions]: unrecognized selector sent to instance 0x10018e270

您可以打印 FinderWindow 的属性:

NSLog(@"properties == %@", [finderWindow properties]);

产生类似的东西:

properties == {
bounds = "NSRect: {{173, 289}, {1241, 663}}";
closeable = 1;
collapsed = 0;
columnViewOptions = "<SBObject @0x1fc5d010: columnViewOptions of
     FinderFinderWindow id 5696 of application \"Finder\" (78829)>";
currentView = "<NSAppleEventDescriptor: 'clvw'>";
floating = 0;
iconViewOptions = "<SBObject @0x1fc5d550: iconViewOptions of
    FinderFinderWindow id 5696 of application \"Finder\" (78829)>";
id = 5696;
index = 2;
listViewOptions = "<SBObject @0x1fc5cca0: listViewOptions of 
    FinderFinderWindow id 5696 of application \"Finder\" (78829)>";
modal = 0;
name = Applications;
objectClass = "<NSAppleEventDescriptor: 'brow'>";
position = "NSPoint: {173, 289}";
resizable = 1;
sidebarWidth = 0;
statusbarVisible = 1;
target = "<FinderFolder @0x1fc5db10: FinderFolder \"Applications\"
     of startupDisk of application \"Finder\" (78829)>";
titled = 1;
toolbarVisible = 1;
visible = 1;
zoomable = 1;
zoomed = 0;
}

【讨论】:

  • 有趣。如果我在检索到 FinderFolder *folder 对象后插入您的 NSLog() 调用以输出 FinderFolder *folder 对象的值,我会得到完全相同的结果(看起来与您报告的非常相似),无论我是否打扰转换为 HFS格式或直接传递NSURL 对象。看来我绝对应该放弃不必要的电话。但是,代码仍然不起作用; Scripting Bridge 返回的任何对象最终仍然没有返回有效的iconSize 值——在检索文件夹和结束之间一定有问题。
  • 现在我考虑到这一点,因为您的建议相当明确地表明我们正在获得一个好的 Finder 文件夹参考,所以这似乎是我尝试的主要候选人并检索关联的窗口引用。
  • 也许不是。我添加了一个类似的NSLog() 调用来显示[[folder containerWindow] get] 调用返回的值,它也返回了一个半有效的响应:folderWindow == &lt;FinderFinderWindow @0x1937ccf0: FinderFinderWindow id 9729 of application "Finder" (12671)&gt;。但是尝试NSLog(@"folderWindow id == %@", [folderWindow id])(或NSLog(@"folderWindow id == %d", [folderWindow id]))仍然失败。
【解决方案2】:

添加一些检查以确保 finder、folderURL 和 folderPathHFS 都有效。脚本桥可能会返回一个表示“无值”而不是 nil 的对象,并且该对象可能会返回另一个“无值”对象,因此您的任何检查都不会触发,因为它们都不是 nil,但是当您请求带有原始类型,它返回 0。

【讨论】:

  • 好主意,但似乎这不是问题所在。我注释掉了所有错误检查if 语句和相应的括号,以便始终为所有对象打印[SBObject lasterror] 的结果,并且它们只是返回重复的(null) 值。 (10.6 的 Scripting Bridge 文档建议,如果发生错误情况,lastError: 选择器将始终返回一些有意义的值。)所以,我认为这不能完全解决它。
  • 由于我提到的 3 个变量不是脚本桥 API 的一部分,它们不会导致错误。尝试获取不存在的文件夹可能不会被视为错误。只要确保这些变量都不为零。
  • 确实如此,但我的印象是 Scripting Bridge 基本上是将工作交给 Finder,如果我(错误地)询问,它应该会发出某种错误对某种无效对象的引用。不过,我可能错了……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-07
  • 1970-01-01
  • 1970-01-01
  • 2019-10-24
  • 2017-07-25
  • 1970-01-01
相关资源
最近更新 更多