4

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

基本上,我正在尝试访问 Finder 窗口的一些显示选项。我有以下代码块作为我的测试用例。我将它指向一个显示为图标的文件夹,我运行代码时,没有一个错误块跳闸,但我总是在最后得到一个无意义的响应(iconSize = 0)。

    // 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 检索对象并将调用标记到各种 SB 相关赋值语句的末尾时,我尝试打印出类名[SBObject *get],但无济于事。

有任何想法吗?


更新

好的,所以我在上面的代码中发现了错误是在哪里产生的,尽管我觉得我离解决问题还差得远。事实证明,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调用之前一切正常。

4

2 回答 2

3

它看起来像是-objectAtLocation:期待一个NSURL而不是 HFS 样式的路径:

讨论

此方法是objectAtIndex:“索引”不仅仅是整数的应用程序的概括。例如,Finder 可以使用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 中一样,是隐含的/可选的/多余的。

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

-[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;
}
于 2011-04-07T03:06:54.167 回答
1

Add some checks to make sure finder, folderURL, and folderPathHFS are all valid. The scripting bridge may return an object representing "no value" instead of nil, and that object could return another "no value" object, so none of your checks will trigger because none of them are nil, but when you ask for something with a primitive type, it returns 0.

于 2011-04-07T00:54:32.123 回答