代码之家  ›  专栏  ›  技术社区  ›  Ryan Pendleton

用类别扩展iTunesApplication类

  •  2
  • Ryan Pendleton  · 技术社区  · 15 年前

    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
    

    有什么特别的我可以做的工作,因为我不能包括符号?


    瑞安·彭德尔顿

    更新:

    3 回复  |  直到 15 年前
        1
  •  1
  •   Ryan Pendleton    11 年前

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

    这是创建类别的.h和.m文件。注意如何 lowerVolume 不是实际的方法,而是带有参数的C函数 id self ,和 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将它们实际添加到scripting bridge类中。我会做这个的 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];
    }
    

    如果这些都说不通,告诉我,我会尽量解释清楚的。

        2
  •  0
  •   TooTallNate    15 年前

    我认为你需要包括 -framework ScriptingBridge 你的海合会论点。那是为我准备的!

        3
  •  0
  •   Ron Reuter    10 年前

    我发现最好的解决方案是在存在的类中使用您的类别,SB应用。下面是我测试过的代码,它可以工作,并完成了原始示例所要做的工作:

    //  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];
    }