Objective-C脚本桥和Apple远程桌面

Objective-C脚本桥和Apple远程桌面,objective-c,cocoa,applescript,scripting-bridge,Objective C,Cocoa,Applescript,Scripting Bridge,尝试通过Objective-C中的脚本桥自动查看Apple Remote Desktop中的计算机,方法如下: @try { SBApplication *RD = [SBApplication applicationWithBundleIdentifier:@"com.apple.RemoteDesktop"]; // (code to check for ARD running and installed omitted here)

尝试通过Objective-C中的脚本桥自动查看Apple Remote Desktop中的计算机,方法如下:


    @try {
        SBApplication *RD = [SBApplication applicationWithBundleIdentifier:@"com.apple.RemoteDesktop"];

        // (code to check for ARD running and installed omitted here)
        [RD activate]; // works just fine

        RemoteDesktopComputer *computer = [[[RD classForScriptingClass:@"computer"] alloc]     initWithProperties:
            [NSDictionary dictionaryWithObjectsAndKeys:
                ipAddress,@"InternetAddress", // looked up from header
                nil
             ]
        ];

        // attempt to add it to a container first:
        [(SBElementArray*)[(RemoteDesktopApplication*)RD computers] addObject:computer]; 
        // this is what raises the exception:
        [computer observeZooming:Nil];
    }
    @catch (NSException *e) {
        NSLog(@"Exception: %@", [e description]);
    }
运行此操作会在日志中产生以下异常:

    Exception: *** -[SBProxyByClass observeZooming:]: object has not been added to a container yet; selector not recognized [self = 0x6050004819b3]
我已经做了很多关于这个主题的研究,并且了解到SB不是最容易处理的,因为它是如何在引擎盖下连接的,但是任何本地脚本桥的专家或老手(请不要使用除obj-c之外的第三方框架或语言)都非常感谢

所有先决条件(如链接到ScriptingBridge.framework和导入远程桌面.h)都已执行-类型转换是为了避免在构建时出现不可避免的链接时间错误

编辑1:阅读关于SBObject(RemoteDesktopComputer的父对象)的文档时说,它是一个引用,而不是一个实际实例,您可以通过调用SBObject的get方法(返回id)获取它。所以我也试着运行这个,但不幸的是得到了同样的结果:

    [[computer get] observeZooming:Nil];
以下是有关SBObject的文档:


仍在尝试…

脚本桥是一个有缺陷的、模糊的混乱,因此当应用程序命令无法工作时,您不知道问题是SB有缺陷还是应用程序本身有缺陷,或者只是要求您以不同的方式对其进行表述

因此,第一步是在AS中编写测试脚本,以查看它是否在AS中工作。如果是这样的话,那就是某人在胡说八道;如果没有,请尝试修改您的AS代码(例如,尝试以不同的方式使用
at
参数的引用,或者完全忽略它),直到完成为止

你还应该询问苹果的AppleScript用户和ARD邮件列表,以及ARD脚本编写者可能会去的任何其他地方,因为大多数应用程序的脚本编写文档都严重不足,所以很多关于如何操作的知识都是口耳相传的。(你真正想找的人是John C Welch,又名
@bynkii
,因为他是ARD脚本的大师。)

(FWIW,我已经有了以下的写作方法,所以我将其留在这里以备将来参考。)


如何使用AppleScript ObjC代替脚本桥 脚本桥充其量是一个80/20/80“解决方案”(即80%的时间工作,20%的时间失败,80%的时间你不知道为什么)。当某人在AppleScript中工作得非常好的东西上出现问题时,试图与他争论是没有什么意义的——负责设计的苹果工程师故意这样做,只是拒绝接受他们违反了规范[1]并搞砸了。因此,尽管AppleScript语言存在其他缺陷,但它仍然是唯一能够保证正确说出Apple事件的受支持解决方案[2]

幸运的是,自OSX10.6以来,还有另一个选项可用:对所有常规编程内容使用ObjC,对IPC内容只通过AppleScript ObjC桥调用AppleScript

从ObjC代码的角度来看,基于AppleScript的ASOC“类”与常规ObjC类几乎没有区别。它需要一点摆弄来设置,而且过桥时你要付一点通行费,但是考虑到备选方案的残废和不可靠性质,它是支持的选项中最不可怕的一个,对于任何非琐碎的东西

假设您已经有一个基于ObjC的现有项目,下面介绍如何向其中添加基于ASOC的类:

  • 在Targets>APPNAME>buildphases>linkbinary与库中,添加
    AppleScriptObjC.framework

  • 在支持文件>
    main.m
    中,添加导入和加载行,如图所示:

    #import <Cocoa/Cocoa.h>
    #import <AppleScriptObjC/AppleScriptObjC.h>
    
    int main(int argc, const char * argv[]) {
       [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts];
       return NSApplicationMain(argc, argv);
    }
    
    以及包含其实现的
    MyStuff.applescript
    文件:

    -- MyStuff.applescript
    
    script MyStuff
    
       property parent : class "NSObject"
    
       on square_(aNumber)
           return aNumber ^ 2
       end square_
    
    end script
    
  • 因为
    MyStuff
    类没有ObjC实现,所以链接器无法在构建时将您的ObjC代码链接到它。相反,请使用
    NSClassFromString()
    在运行时查找类对象:

    #import "MyClass.h"
    
    ...
    
    MyStuff *stuff = [[NSClassFromString(@"MyStuff") alloc] init];
    
    否则,它与正常使用中的本机ObjC类几乎没有区别:

    NSNumber *result = [stuff square: @3];
    NSLog(@"Result: %@", result);
    
  • --

    [1] 苹果管理层在最初发布AppleScript后不久就解散了最初的AppleScript团队,导致其设计师因此辞职,因此失去了很多关于这项技术应该如何工作的知识。特别是,应用程序开发人员在设计其脚本支持时,从来没有制定过完整、正式的规范,因此他们所能做的就是使用个人判断和最佳猜测,然后对AppleScript进行测试,以检查它是否按预期工作。因此,AppleScript自己的Apple事件桥接器是过去二十年中每个可编写脚本的应用程序都已实现的事实规范,因此其他AE桥接器能够正确工作的唯一方法是,如果它们模仿AS自己的桥接器,直到每一个查询和怪癖-不幸的是,这是一个教训,当前AS团队多次未能理解[2]


    [2] 顺便说一句,Automation的Apple event支持的JavaScript同样差劲且失败。

    您能检查哪个函数抛出异常(例如,通过使用异常断点)吗?进入observeZooming:只需像不使用断点一样抛出异常,确认observeZooming:确实是触发异常的方法,但没有给出任何关于原因的见解。查看我的编辑-尝试使用和不使用“get”选择器来取消引用对象,每次都得到相同的结果我没有使用脚本桥,因此我可能无法想出解决方案,但
    [RD computers]
    的返回值是否为非零?我使用NSLog输出运行了一些测试代码来检查,它确实不是零。。。但是,这可能是因为一些正在进行的去引用抽象——请查看以下详细解释:非常有用,谢谢!希望这对其他人有帮助。
    NSNumber *result = [stuff square: @3];
    NSLog(@"Result: %@", result);