Pregunta

Estoy aprendiendo cómo utilizar ScriptingBridges. Hice un método que se desvanece poco a poco el volumen en iTunes, y me gustaría hacer una categoría para que pueda hacer lo siguiente:

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

Me hizo otra categoría para NSSpeechSynthesizer que las obras, pero no puedo conseguir éste a. Sigo recibiendo el siguiente error de compilación:

"_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

¿Hay algo especial que pueda hacer para que funcione ya que no puedo incluir los símbolos?

Gracias,
Ryan Pendleton

ACTUALIZACIÓN: Sólo he encontrado una solución, que está por debajo. Se trata de MethodSwizzling, así que estoy abierto a mejores respuestas, pero por ahora es todo lo que tengo.

¿Fue útil?

Solución

La solución que encontré fue utilizar la API de tiempo de ejecución de Objective-C. Estoy seguro de que hay una mejor manera de organizar esto, pero aquí está cómo lo hice:

Aquí están mis .hy .m archivos para la creación de la categoría. Observe cómo lowerVolume no es un método real, sino una función C con el id self argumentos, y SEL _CMD. También se dará cuenta de una función setupCategories. Llamaremos a esto más adelante.

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

Ahora que he hecho las funciones, necesito agregar realmente a la clase puente de secuencias de comandos utilizando la API de tiempo de ejecución de Objective-C. Voy a hacer esto en main.m para asegurarse de que los métodos están listos para ser utilizados cuando el bucle se vuelve a comenzar.

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

Ahora, puedo usar mi método donde quiera, siempre y cuando incluyo los archivos de cabecera:

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

Si nada de esto no tiene sentido, sólo dime y voy a tratar de explicarlo mejor.

Otros consejos

Creo que es necesario incluir -framework ScriptingBridge a sus argumentos gcc. Eso hizo que se compile para mí!

Como se señaló anteriormente, no se puede hacer fácilmente una categoría en iTunesApplication, ya que no existe en tiempo de compilación, y también porque el nombre de la clase en tiempo de ejecución es ITunesApplication ( "I" mayúscula).

La mejor solución que he encontrado es hacer su categoría en la clase que existe, SBApplication. Aquí está el código que he probado que funciona y lo que el ejemplo original, estaba tratando de hacer:

//  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];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top