在 10.6 下,通过 Scripting Bridge 调用 Finder,返回值不正确(但不会抛出错误)

发布于 2024-10-28 07:37:58 字数 3002 浏览 6 评论 0 原文

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

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

    // 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 相关的赋值语句的末尾,但无济于事。

有什么想法吗?


更新

好的,所以我已经发现了上面代码中生成错误的位置,尽管我觉得我距离修复问题还差得远。问题。事实证明,脚本桥的惰性评估掩盖了问题。如果在检索对 FinderWindow 的引用后,插入以下两行代码:

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

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

Return value == (null);错误消息==操作无法完成。 (OSStatus 错误 -1700。)

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

I've been skimming lots and lots of Scripting Bridge-related threads on StackOverflow and elsewhere, and can't seem to make any headway on figuring out why a block of Cocoa code that makes a Scripting Bridge call to the Finder no longer works correctly under 10.6. (A similar version of the code seemed to work OK under 10.5, and I don't know what caused the change in behavior.)

Basically, I'm trying to access some of the display options for a Finder window. I have the following block of code as my test case. I'm pointing it at a folder that is displaying as icons, and when I run the code, none of the error blocks trip, but I always just get a nonsensical response (iconSize = 0) at the end.

    // 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");
    }

The pure AppleScript version of this code works fine, even when pointing to the same folder:

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

My gut instinct is that something is being cast or converted oddly as it's passing through the Scripting Bridge, but I'm completely out of ideas about what to check or where else to look. I've tried printing out class names along the way as objects are retrieved from the Finder and tagging [SBObject *get] calls onto the end of various SB-related assignment statements, but to no avail.

Any ideas?


UPDATE

OK, so I've discovered where the error is being generated in the code above, although I don't feel like I'm all that much closer to fixing the problem. It turns out that the Scripting Bridge's lazy evaluation was masking the problem. If, after retrieving the reference to the FinderWindow, you insert the following two lines of code:

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

Then, Scripting Bridge tries to actually execute the name retrieval, fails, and comes back with a slightly-more-constructive error message:

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

This is awesome (progress?!), but still doesn't get me a whole lot closer to solving the problem. That error message seems to indicate that there's an AEcoercion problem someplace, but I'm not sure how to proceed in solving it. The generated Finder.h file (and the Finder's AppleScript Dictionary) are both pretty clear about the fact that I should be getting back a reference to a FinderWindow object, and printing the folderWindow object out seems to verify that everything is OK up until the name call.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初见你 2024-11-04 07:37:58

它看起来像 -objectAtLocation:< /code> 需要一个 NSURL 而不是 HFS 样式的路径:

讨论

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

我刚刚尝试了使用 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 ==

(注意:我在创建 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]时收到无法识别的选择器错误消息:

-[SBObject iconViewOptions]:无法识别的选择器发送到实例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;
}

It looks like -objectAtLocation: is expecting an NSURL as opposed to an HFS-style path:

"Discussion

This method is a
generalization of objectAtIndex: for
applications where the "index" is not
simply an integer. For example, Finder
can specify objects using a NSURL
object as a location. In OSA this is
known as "absolute position," a
generalization of the notion of
“index” in Foundation—it could be an
integer, but it doesn't have to be. A
single object may even have a number
of different "absolute position"
values depending on the container."

I just tried code that used an NSURL and it worked okay. For example, the following code

- (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);
    }
}

produced the following output:

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

(Note: I used different parameters when creating the Finder.h file (to prevent confusing names like FinderFinderWindow), so my class names will be slightly different).

So, your code should probably work provided it's changed to the following:

// 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");
}

UPDATED:
There should be no need for your added -get call; get is implied/optional/superfluous just like in regular AppleScript.

I'm getting an unrecognized selector error message when trying to get [folderWindow iconViewOptions]:

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

You can print the properies of the FinderWindow though:

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

produces something like:

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;
}
仅冇旳回忆 2024-11-04 07:37:58

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文