Swift and scriptingbridge object initialization

前端 未结 4 1943
天命终不由人
天命终不由人 2021-02-03 14:45

I\'m trying to write an application for swift control iTunes. But when initializing the application returns an object of type AnyObject, but must iTunesApplication.

相关标签:
4条回答
  • 2021-02-03 15:28

    In my swift project , I had issues with using the types defined in the generated iTunes.h file (linking errors and such).

    The answer from markhunte explains that you can obtain a reference to the application object. But beyond that, I was getting compilation/linker errors when trying to obtain instances from that application object.

    In my swift project, I ended up creating an objective C wrapper class that exposes the iTunes types as basic objective C types (arrays and dictionary), and adapts methods as well.

    My swift classes use this wrapper instead of the iTunes types.

    So, the objective C wrapper looks like this (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
    

    and the calling swift code:

    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)")
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-03 15:33

    I wrote a Python script to generate Scripting Bridge headers and then automatically make a native Swift version. That way you don't have to deal with writing full wrappers or even using a Bridging Header. Also, no worry of Linker Errors because it's completely in Swift. https://github.com/garrett-davidson/SwiftingBridge/

    0 讨论(0)
  • 2021-02-03 15:33

    An inelegant way to do work around the issue is to have iTunes declared as an SBApplication, then, when you call a function from iTunesApplication, downcast iTunes to an AnyObject:

    (iTunes as AnyObject).play()
    

    Note that there is no type-safety if you do this: you could call any function declared in any Objective-C header: it's just not guaranteed to be implemented in a specific class, and thus will crash the program.

    0 讨论(0)
  • 2021-02-03 15:36

    I suspected that the problem was that the iTunes.h file was not being imported. Therefore it's methods where not being picked up.

    So I created a -Bridging-Header.h file.

    My Project is name swiftItunesTest. so the -Bridging-Header.h file is named:

    swiftItunesTest-Bridging-Header.h

    Inside of this I placed the #import "iTunes.h" line

    And in the AppDelegate.swift file

    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
        }
    
    
    }
    

    The iTunesApplication (iTunes.) now started to pick up the methods/functions


    Here is a slightly updated example.

     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 讨论(0)
提交回复
热议问题