在10.6下使用Scripting Bridge调用Finder时返回值不正确(但非错误)

时间:2011-03-31 23:43:36

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

我一直在StackOverflow和其他地方浏览大量与Scripting Bridge相关的线程,并且似乎无法弄清楚为什么一块Cocoa代码使得Scripting Bridge调用Finder no更长时间在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中检索对象并将[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.)

这很棒(进步?!),但仍然没有让我更接近解决问题。该错误消息似乎表明在某个地方存在AE强制问题,但我不确定如何继续解决它。生成的Finder.h文件(以及Finder的AppleScript字典)都非常清楚我应该返回对FinderWindow对象的引用,打印folderWindow对象似乎验证一切正常直到name来电。

2 个答案:

答案 0 :(得分:3)

看起来-objectAtLocation:期待NSURL而不是HFS风格的路径:

  

“的讨论

     

这个方法是一个   objectAtIndex:的推广   “索引”不适用的应用程序   只是一个整数。例如,Finder   可以使用NSURL指定对象   对象作为位置。在OSA中这是   被称为“绝对位置”,a   概念的概括   在基金会的“索引” - 它可能是一个   整数,但不一定是。一个   单个对象甚至可能有一个数字   不同的“绝对位置”   价值取决于容器。“

我刚试过使用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;
}

答案 1 :(得分:1)

添加一些检查以确保finderfolderURLfolderPathHFS都有效。脚本桥可能会返回一个表示“无值”而不是nil的对象,并且该对象可以返回另一个“无值”对象,因此没有任何一个检查会触发,因为它们都不是nil,而是当你要求某个东西时原始类型,它返回0。