2

我只是在学习如何使用 ScriptingBridges。我做了一种方法,可以慢慢淡化 iTunes 上的音量,并希望将其设为一个类别,以便我可以执行以下操作:

iTunesApplication* iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];
[iTunes lowerVolume:50 speed:1];

我为 NSSpeechSynthesizer 制作了另一个有效的类别,但我无法得到这个。我不断收到以下构建错误:

"_OBJC_CLASS_$_iTunesApplication", referenced from:
l_OBJC_$_CATEGORY_iTunesApplication_$_iTunesApplicationAdditions in iTunesApplication.o
objc-class-ref-to-iTunesApplication in iTunesApplication.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

由于我不能包含符号,因此我可以做些什么特别的事情来使它工作?

谢谢,
瑞恩彭德尔顿

更新: 我只找到了一个解决方案,如下所示。它涉及 MethodSwizzling,所以我愿意接受更好的答案,但现在这就是我所拥有的。

4

3 回答 3

1

我找到的解决方案是使用 Objective-C 运行时 API。我确信有更好的方法来组织它,但我是这样做的:

这是我用于创建类别的 .h 和 .m 文件。注意 howlowerVolume不是一个实际的方法,而是一个带有参数id self和的 C 函数SEL _CMD。您还会注意到一个setupCategories函数。我们稍后会调用它。

// iTunes+Volume.h

#import <objc/runtime.h>
#import "iTunes.h"

void lowerVolume(id self, SEL _cmd, int dest, float speed);
void setupCategories();

@interface iTunesApplication (Volume)

- (void)lowerVolume:(int)dest speed:(float)speed;

@end

// iTunes+Volume.m

#import "iTunes+Volume.h"

void lowerVolume(id self, SEL _cmd, int dest, float speed)
{
    NSLog(@"Lower Volume: %i, %f", dest, speed);
}

void setupCategories()
{
    id object = [[SBApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"];
    Class class = [object class];
    [object release];

    class_addMethod(class, @selector(lowerVolume:speed:), (IMP)lowerVolume, "@:if");
}

现在我已经创建了函数,我需要使用 Objective-C 运行时 API 将它们实际添加到脚本桥接类中。我将这样做main.m以确保在运行循环开始时可以使用这些方法。

// main.m

#import <Cocoa/Cocoa.h>
#import "iTunes+Volume.h"

int main(int argc, char *argv[])
{
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    setupCategories();
    return NSApplicationMain(argc,  (const char **) argv);

    [pool drain];
}

现在,只要包含头文件,我就可以在任何地方使用我的方法:

- (void)mute
{
    iTunesApplication* iTunes = [[SBApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"];
    [iTunes lowerVolume:0 speed:1];
    [iTunes release];
}

如果其中任何一个没有意义,请告诉我,我会尝试更好地解释它。

于 2011-04-11T21:31:35.313 回答
0

我认为您需要包含-framework ScriptingBridge在您的 gcc 参数中。这让它为我编译!

于 2011-04-11T06:03:24.190 回答
0

如上所述,您不能轻易地在 iTunesApplication 上创建一个类别,因为它在编译时不存在,而且运行时类名称是 iTunesApplication(大写“I”)。

我找到的最好的解决方案是在确实存在的类 SBApplication 上做你的类别。这是我测试的代码,它可以正常工作,并且可以执行原始示例尝试执行的操作:

//  SBApplication+Extensions.h

@import ScriptingBridge;

@interface SBApplication (Extensions)

- (void)lowerVolume:(int)dest speed:(float)speed;

@end

//  SBApplication+Extensions.m

#import "iTunes.h"
#import "SBApplication+Extensions.h"

@implementation SBApplication (Extensions)

- (void)lowerVolume:(int)dest speed:(float)speed
{
    NSLog(@"Lower Volume: %i, %f", dest, speed);
}

@end

// Caller, say in AppDelegate

#import "SBApplication+Extensions.h"

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{

    iTunesApplication *iTunesApp =
        [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"];

    [iTunesApp lowerVolume:4 speed:3.3f];
}
于 2016-03-19T03:51:53.280 回答