2014-06-06 16 views
5

Sto provando a scrivere un'applicazione per il controllo rapido di iTunes. Ma quando si inizializza l'applicazione restituisce un oggetto di tipo AnyObject, ma deve essere iTunesApplication.Inizializzazione di oggetti Swift e scriptingbridge

Questo oggetto non risponde ai metodi e alle variabili iTunes. Chi sa come farlo funzionare?

var iTunes = SBApplication.applicationWithBundleIdentifier("com.apple.iTunes") 

L'intestazione iTunes.h contiene anche le classi che è necessario accedere ma non è possibile. Queste classi causano un errore di compilazione come se non fossero in un iTunes.h dichiarato.

Perché ciò che sta succedendo a me non è ancora chiaro.

L'intero elenco delle classi che sono dichiarata iTunes.h in via @class:

iTunesPrintSettings @class, iTunesApplication, iTunesItem, iTunesAirPlayDevice, iTunesArtwork, iTunesEncoder, iTunesEQPreset, iTunesPlaylist, iTunesAudioCDPlaylist, iTunesLibraryPlaylist, iTunesRadioTunerPlaylist, iTunesSource , iTunesTrack, iTunesAudioCDTrack, iTunesFileTrack, iTunesSharedTrack, iTunesURLTrack, iTunesUserPlaylist, iTunesFolderPlaylist, iTunesVisual, iTunesWindow, iTunesBrowserWindow, iTunesEQWindow, iTunesPlaylistWindow;

Per esempio in Objective - c si può usare qualcosa di simile a questo per ottenere la traccia corrente

iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; 
NSLog(@"Current song is %@", [[iTunes currentTrack] name]); 

Ma io non può ottenere un equivalente in rapida per lavorare.

+0

Quando si esegue println ("\ (iTunes.className)") 'restituisce" ITunesApplication " – markhunte

+0

Errore del compilatore -" AnyObject non ha un membro denominato className " –

+0

Sì. L'ho visto nei miei test. Stavo rilevando che, sebbene fornisca quell'errore, è classificato come ITunesApplication. posso anche suggerire di aggiungere più dettagli alla tua domanda. su cosa hai provato a risolvere questo problema e su come stai importando il file iTunes.h, ecc. So che per primo mi aspettavo xcode da offrire per aggiungerlo a un file di importazione dell'intestazione, ma non ne ho mai ottenuto uno. – markhunte

risposta

3

Ho il sospetto che il problema era che il file iTunes.h non veniva importato. Quindi sono i metodi in cui non vengono raccolti.

Così ho creato un file -Bridging-Header.h.

Il mio progetto è nome swiftItunesTest. quindi il file -Bridging-header.h prende il nome:

swiftItunesTest-Bridging-header.h

All'interno di questo ho messo il #import "iTunes.h" linea

E nel file AppDelegate.swift

import Cocoa 
import Appkit 
import ScriptingBridge 





class AppDelegate: NSObject, NSApplicationDelegate { 

    @IBOutlet var window: NSWindow 


    func applicationDidFinishLaunching(aNotification: NSNotification?) { 
     var iTunes : AnyObject = SBApplication.applicationWithBundleIdentifier("com.apple.iTunes") 

     iTunes.playpause() 


    } 

    func applicationWillTerminate(aNotification: NSNotification?) { 
     // Insert code here to tear down your application 
    } 


} 

i iTunesApplication (iTunes). ora iniziate a raccogliere i metodi/funzioni


Ecco un esempio leggermente aggiornato.

func applicationDidFinishLaunching(aNotification: NSNotification) { 
     let iTunes : AnyObject = SBApplication(bundleIdentifier: "com.apple.iTunes")! 

     iTunes.playpause() 


      guard let currentTrack: AnyObject = iTunes.currentTrack!.name else { 

      print("No Tracks Playing") 
      return 
     } 
      print("\(currentTrack)") 

    } 

    func applicationWillTerminate(aNotification: NSNotification) { 

    } 
+0

@jQwierdy questo è un vecchio post e swift è cambiato da allora, quindi non sarei sorpreso se avesse lanciato un errore ora, ma al momento della pubblicazione funzionava tutto come ho detto. Da allora non ho giocato molto con ScriptingBridge. Soprattutto perché non ne avevo bisogno e anche perché è stato un tale dolore usare per tutte le ragioni per cui questo post è nato. – markhunte

+0

@jQwierdy Tutto ciò che ho fatto per far funzionare di nuovo è stato modificare la linea Var di iTunes in: 'let iTunes: AnyObject = SBApplication (bundleIdentifier:" com.apple.iTunes ")!' – markhunte

+0

Hai ragione, ho fatto uno stupido commento - Mi dispiace per quello. Stupido da parte mia, non ho compreso appieno il significato del fatto che AnyObject è il tipo di ID di ObjC, perché significa che è digitato in modo dinamico. Qualunque mio compilatore ha generato un errore ma era per un motivo diverso. Mi dispiace per quello La tua risposta è buona. – jQwierdy

7

Nel mio progetto veloce, ho avuto problemi con l'utilizzo di tipi definiti nel file iTunes.h generato (che collegano errori e simili).

La risposta di markhunte spiega che è possibile ottenere un riferimento all'oggetto dell'applicazione. Oltre a ciò, ricevevo errori di compilazione/linker quando cercavo di ottenere istanze da quell'oggetto dell'applicazione.

Nel mio progetto rapido, ho finito per creare una classe di wrapper C oggettiva che espone i tipi di iTunes come tipi di obiettivi C di base (array e dizionario) e adatta anche i metodi.

Le mie classi veloci utilizzano questo wrapper al posto dei tipi di iTunes.

Così, il C involucro obiettivo si presenta così (redux):

#import "ITunesBridgex.h" 
#import "iTunes.h" 

@interface ITunesBridgex(){ 
    iTunesApplication *_iTunesApplication; 
    iTunesSource* _iTunesLibrary; 
} 
@end 
@implementation ITunesBridgex 

-(id)init { 
    self = [super init]; 
    if (self) { 
     _iTunesApplication = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; 
     NSArray *sources = [_iTunesApplication sources]; 
     for (iTunesSource *source in sources) { 
      if ([source kind] == iTunesESrcLibrary) { 
       _iTunesLibrary = source; 
       break; 
      } 
     } 
    } 
    return self; 
} 

- (NSDictionary*) currentTrack { 
    iTunesTrack* track = _iTunesApplication.currentTrack; 
    if (!track) 
     return nil; 
    NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: track.name, @"title", nil]; 
    return dict; 
} 

@end 

e il chiamante codice swift:

import Foundation 
import Cocoa 

class ITunesBridgeSimple { 

    var iTunesBridgex: ITunesBridgex 

    init(){ 
     iTunesBridgex = ITunesBridgex() 
     self.updateFromCurrentTrack() 
    } 
    func updateFromCurrentTrack() { 
     if let track = self.currentTrack { 
      if let title : AnyObject = track.objectForKey("title"){ 
       println("Current track: \(title)") 
      } 
     } 
    } 
} 
2

ho scritto uno script Python per generare le intestazioni script ponte e poi automaticamente crea una versione nativa di Swift. In questo modo non devi occuparti della scrittura di wrapper completi o anche dell'uso di un Bridging Header. Inoltre, non preoccuparti degli errori del linker perché è completamente in Swift. https://github.com/garrett-davidson/SwiftingBridge/

1

Un modo poco elegante per fare il lavoro di tutto il problema è quello di avere iTunes dichiarata come SBApplication, poi, quando si chiama una funzione da iTunesApplication, abbattuto iTunes a un AnyObject:

(iTunes as AnyObject).play() 

notare che v'è nessuna sicurezza di tipo se si esegue questa operazione: è possibile chiamare qualsiasi funzione dichiarata in qualsiasi intestazione Objective-C: non è garantito che venga implementata in una classe specifica e, quindi, il programma si bloccherà.