Расширьте класс iTunesApplication категориями - PullRequest
2 голосов
/ 07 ноября 2010

Я только учусь использовать 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

Есть ли что-то особенное, что я могу сделать, чтобы это работало, поскольку я не могу включить символы?

Спасибо,
Райан Пендлтон

UPDATE: Я нашел только одно решение, которое ниже. Он включает в себя MethodSwizzling, поэтому я открыт для лучших ответов, но пока это все, что у меня есть.

Ответы [ 3 ]

1 голос
/ 12 апреля 2011

Решение, которое я нашел, состояло в том, чтобы использовать API времени выполнения Objective C.Я уверен, что есть лучший способ организовать это, но вот как я это сделал:

Вот мои файлы .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");
}

Теперь, когда я создал функции, мне нужно добавить их в класс моста сценариев с помощью API-интерфейса Objective-C.Я сделаю это в 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];
}

Если что-то из этого не имеет смысла, просто скажите мне, и я постараюсь объяснить это лучше.

0 голосов
/ 19 марта 2016

Как отмечалось выше, вы не можете легко создать категорию в 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];
}
0 голосов
/ 11 апреля 2011

Я думаю, вам нужно включить -framework ScriptingBridge в ваши аргументы gcc.Вот и скомпилировал для меня!

...