I'd like to use Swift to build an OS X Preference Pane plugin for the System Preferences app, but I can't get it to work.
After clicking "Next" the Xcode template doesn't offer an option to choose Swift as a language, but automatically creates the project in Objective-C.
Without adding any code or doing anything else, the project builds successfully. If you right-click on the Product and select "Open in External Editor", System Preferences will successfully install and load the preference pane.
It just works!
Well that's great, but now, I want to add a new Cocoa subclass using Swift.
Accepting the default, and allowing it to create the Bridging Header.
Now, quit System Preferences and without adding any code, rebuild the project. As before, right-click the Product and "Open in External Editor".
System Preferences will confirm replacing the preference pane, and it will install it, but then it fails to load.
If you show the built Product in the Finder, in addition to the .prefPane plugin, there's also a .swiftmodule folder.
I'm guessing there's something missing in the Build Phases or Build Settings that's responsible for incorporating the .swiftmodule with the rest of the bundle, but haven't been able to figure it out.
After you add some code that uses the new class, it's necessary to import the Swift project umbrella header ("Prax-Swift.h") to make the project compile, but importing the umbrella header doesn't fix this problem.
// Prax.h
#import <PreferencePanes/PreferencePanes.h>
#import "Prax-Swift.h"
@interface Prax : NSPreferencePane
@property PraxObject *ourPrax;
- (void)mainViewDidLoad;
@end
I also tried deleting Prax.h and Prax.m and simply implementing the NSPreferencePane subclass in Swift. As before, the project builds and installs, but System Preferences fails to load it.
// Prax.swift
import PreferencePanes
class Prax: NSPreferencePane {
override func mainViewDidLoad() {
}
}
Sorry if I've used too many pictures in this question; it seemed to be the clearest way to explain the problem and make it easy to reproduce. There's probably a simple solution. Any ideas?
First, you need to enable the "Embedded Content Contains Swift" setting so that Xcode will copy the necessary Swift libraries into the bundle.
Then, you get this error:
This means the app doesn't know where to load the included Swift libraries from.
To fix this, add
@loader_path/../Frameworks
to the runpath search paths in the build settings, telling it that the Swift libraries are in the Frameworks directory of your prefpane:See the dyld man page for further info about dynamic loading.