Xcode pluginDidLoad not getting called when adding objective-c file in swift plugin - objective-c

I'm working on a plugin for Xcode. It is supposed to be written in Swift.
When I start with a fresh plugin project (I'm using this Xcode Plugin template which is also available via Alcatraz) the project compiles and runs fine.
The pluginDidLoad method is getting called right after Xcode starts. As soon as I add any Objective-C file (and a bridging header of course) the pluginDidLoad method is not getting called anymore.
The Objective-C file might be as simple as an empty class that is a subclass of NSObject.
Removing the target-memberbership (for the plugin-target) from the newly created Objective-C (.m) file the aforementioned mentioned method is getting called again.
Has anyone developed a Xcode plugin in Swift that also uses Objective-C files before and got this working?

Update
It seems that my original solution only works with Swift only projects because Xcode always takes the objective c class if you have one.
So here is another trick: Extend the NSObject class by the function class func pluginDidLoad(bundle: NSBundle) {} and initialize your plugin there. Then it doesn't matter on which class it is called. You might have to check that also all Swift classes subclass NSObject. I pushed it to my repository that you can have a look
Original Post
I think I could reproduce the problem now. To simplify the problem, let's say that we have only two swift classes PluginMain and PluginHelper.
As you said, sometimes the plugin isn't getting called for some mysterious reason. I was struggling with the problem again and I was wondering how Xcode knows which class is the main class. So I came up with the idea to put the following initializer in both classes PluginMain and PluginHelper
class func pluginDidLoad(bundle: NSBundle) {
let appName = NSBundle.mainBundle().infoDictionary?["CFBundleName"] as? NSString
if appName == "Xcode" {
//sharedPlugin = SwiftySafe(bundle: bundle)
//initialize your shared plugin
}
}
By putting a breakpoint or log message in pluginDidLoad in both classes, I notices that Xcode isn't ignoring the plugin, it is just loading the wrong class (e.g. PluginHelper instead of PluginMain).
The Solution
It turns out that Xcode uses the class that is compiled first as the main class and calls pluginDidLoad only on that. So you can change that by reordering the "Compiled Sources" under your target settings->Build Phases. Move your main class so that it is on top. In the following image you find an example from my project. SwiftySafe is my main class.
My example
You will find my project here https://github.com/creinders/SwiftySafe if you want to compare the settings.

The pluginDidLoad method is called on the principal class. When the principal class is a Swift class, you have to include the module name in the NSPrincipalClass Info.plist key.
So if your target name is MyPlugin and your principal class is MyClass, set NSPrincipalClass to MyPlugin.MyClass.
Also make sure that MyClass inherits from NSObject.

Sometimes you need to tell Xcode to reload bundle. Run this and restart Xcode
defaults delete com.apple.dt.Xcode DVTPlugInManagerNonApplePlugIns-Xcode-7.3

Related

Swift autogenerated header missing new swift classes

I am working in this project where I have a mix of old pre-ARC et ARC Objective-c files co-existing with swift since the start of the year. For some reason, that I can not find, to day all new Swift files I have added set to public are not being added to the Swift auto-generated header.
I have check target ownerships, build phase, that it is public as #objc and inherits NSObject. still I can not call the class from Objc and I can from other swift class. it is as if it was set to be private to the swift module or something even after setting it access public..
for example :
#objc public class SomeSwiftClass: NSObject
{
public func sayit()
{
print("Hello!")
}
}
this does not show in any of the OBjc classes where project-swift.h is imported. I am able to call previously created classes, but not the one I added today.
I would guess that some setting is wrong if all my classes are no longer available, but no just the new class !!?!??!?!?!?!?!?!?!
Edit:
- restarting Xcode does not fix it.
- rebooting system does not fix it.
- deleting derived data does not fix it.
strange thing building while having 1 line of code in Objc accessing the swift class does not cause an error. So Its looking like some type of problem with code completion.

Using Swift in Objective-C project

Although I have followed and tried everything from This Thread and read all of Apple's Guide of Swift-ObjC interoperability, I'm unable to recognize or use Swift fies in my project.
I have created a Swift file that declares/defines a class called TorusView that inherits from UIView. I've tried to gain access to this class in another class MenuView by importing the bridging header, importing the Swift class, importing the class with the syntax *-swift.h (which seems to now be *.swift.hin Xcode7.2). I've made all of the modifications to my target build settings recommended in that lengthy Stack question and a variety of others from google searches.
Nothing I've tried has allowed me to create a TorusView objective in my objective-C class.
You need to import a header file YourAppName-Swift.h, it contains all the public (and internal if same target) declared types in Swift.
first: Build Settings --> defines module --> YES.
second:Product Module Name -->YOUR project NAME.
last:improt "YOUR project NAME-Swift.h" in your Object-c file
like this:
enter image description here

Cannot extend CocoaPods class in my Swift class

I've tried following the tutorial at https://vimeo.com/107295686, and failed very early.
Basically, I've:
created project
created Podfile which requires BDBOAuth1Manager and AFNetworking
installed cocoapods, closed XCode, and reopened it in my MyProject.xcworkspace directory.
Created and deleted a dummy Objective-C file, because I needed bridging header
Added #include directive to this header, which asks for BDBOAuth[...].h
Created Cocoa Touch class which extends BDBOAuth1RequestOperationManager
This is my code:
import UIKit
class RESTClient: BDBOAuth1RequestOperationManager {
}
And now I can't instantiate my new Cocoa Touch class.
When I try to call constructor, this is the hint I get
Note that method description says "Initializes an instance of the class that implements the video compositing protocol", which has nothing to do with my OAuth intentions. When I switch back to my class, and command-click the class I've tried to extend, I get the correct file with correct init params.
Any help will be appreciated
When I was trying to do this exact thing (same library), I had to change the import statements in BDBOAuth1Manager to use
#import <AFNetworking/xxx.h>.
My project wouldn't build without it. Have you checked the header search paths?

Autocompletion doesn't work for Swift subclass of Objective-C class

I've some problem with Xcode's autocompletion.
I've a project written in swift that include some classes written in Objective-C, all works fine, but when I want to use a Objective-C class in swift Xcode doesn't help me, also if I subclass the original Objective-C class when I use that class Xcode doesn't autocomplete and show me "< < error type > >"
I've already cleaned derived data, restarted Xcode and restart my mac but nothing is changed.
I've also set to yes "Scan all source files for include" and of course ' ve added the correct Bridging-Header.
P.s. the code runs and works, it is only a autocompletion problem

What is the entry point of swift code execution?

There is no main() method in swift. The program must start the execution from somewhere. So what is the entry point of swift code execution and how is it decided?
The entry point in a plain Swift module is the file in the module called main.swift. main.swift is the only file which is allowed to have expressions and statements at the top level (all other Swift files in the module can only contain declarations).
Cocoa Touch uses the #UIApplicationMain attribute on an implementation of UIApplicationDelegate instead of a main.swift file to mark the entry point. Cocoa used to use a minimal main.swift file which simply called NSApplicationMain, but as of Xcode 6.1 uses the #NSApplicationMain attribute on an implementation of NSApplicationDelegate.
In the AppDelegate.swift file you can see #UIApplicationMain.
The AppDelegate is the initial entry file.
Basically: main.m and AppDelegate.m are kinda merged in Swift to just AppDelegate.swift
You may want to read Files and Initialization
The exception is a special file named “main.swift”, which behaves much
like a playground file, but is built with your app’s source code. The
“main.swift” file can contain top-level code, and the order-dependent
rules apply as well. In effect, the first line of code to run in
“main.swift” is implicitly defined as the main entrypoint for the
program. This allows the minimal Swift program to be a single line —
as long as that line is in “main.swift”.
In Xcode, Mac templates default to including a “main.swift” file, but
for iOS apps the default for new iOS project templates is to add
#UIApplicationMain to a regular Swift file. This causes the compiler
to synthesize a main entry point for your iOS app, and eliminates the
need for a “main.swift” file.
Alternatively, you can link in an implementation of main written in
Objective-C, common when incrementally migrating projects from
Objective-C to Swift.
In Swift 5.3 there is a new #main attribute which lets you control where your entry point is in your project rather than just main.swift. There can only be one main entry and you can't have a main.swift file and a an attribute #main. See https://github.com/apple/swift-evolution/blob/master/proposals/0281-main-attribute.md for more details.
#main
struct App {
static func main() {
print("Starting.")
}
}
In Swift apps there are attributes:
#UIApplicationMain (Cocoa Touch)
#NSApplicationMain (Cocoa)
that tell the swift compiler where is the entry point of the application.
What swift compiler does under the hood is that it creates a main function, which basically looks the same as in Objective-C apps and treats this method as the app's entry point (a first method that is called when the application process is started).
If you want to read more about what swift compiler does with Main attributes, how the OS knows where is the entry point of the application, I encourage you to read this article: Understanding iOS app entry point
The entry point in a plain Swift module is the file in the module called.