Xcode 6 crashing when using Objective-C subproject inside Swift - objective-c

I have a fairly large Obj-C library that's a subproject in Xcode in several Obj-C projects and it works well.
I'm trying to use that same library in a Swift project but it's crashing Xcode when it gets to a variable declaration of one of the types from my library.
The headers seem to be working because auto-complete sees the proper types from my library. I've added my library (libMylib.a) in Link Binary with Libraries just like in my other Obj-C projects.
class thing {
var width: CGFloat
// more variables
var foo: MyClass // this is a class contained in my subproject
// functions, etc..
}
It crashes Xcode if the var foo line is there, not even when I create or access it. If it's just there. That's why I think it has something to do with not linking the subproject properly or similar.
Not sure what I'm missing.
Thanks.

Related

Problem with using Swift in Objective-C target

I have an old Objective-C project, which has multiple targets, and some of the targets share a framework (let's call it CJDataKit) that's also written in Objective-C. I'm trying to add some Swift code to my project, at least to the main app target, and have some limited implementation of it working, but I'm running into some issues whenever the Swift code needs to use or import the CJDataKit framework, or any header file that itself imports the CJDataKit framework.
What's Working
I wrote a basic UIView subclass in Swift (which didn't need any other code from my app), and I can use this in my Objective-C target, using #objc keyword and by importing "MyApp-Swift.h" in my Objective-C code.
I then wrote a new UIViewController subclass in Swift, and used a couple of simple Objective-C objects from both CJDataKit framework and non-framework classes. I did this by creating a bridging header file, and added the Objective-C headers there.
So far so good, and everything compiles fine.
What's Not Working
The problem happens if I try to import into Swift other Objective-C
files that might be importing the CJDataKit framework inside it. For
e.g. I wanted to write a Swift extension of an existing
UIViewController subclass (call is PageAViewController). This
subclass has imported multiple other header files. If I add it to the
bridging header file, I start getting build errors:
Include of non-modular header inside framework module 'CJDataKit':
'.../CJDataKit/Person.h'
Commenting out the #import CJDataKit makes it work for this particular file, but it still gets compile errors from a different header file (that was imported by PageAViewController). It'll only work if all the files imported don't have a #import CJDataKit, which is difficult and cumbersome. BTW, these files all belong to the app target, not the framework. So something about Swift doesn't like interacting with the CJDataKit framework directly, even though it works fine if it's built independently in the same app target along with the CJDataKit framework.
I've also tried importing the CJDataKit.h header file into the Swift
bridging header file, figuring this way I don't have to individually
import each file from the framework, but that doesn't work either.
That results in a different error:
Could not build module 'CJDataKit.h'
I've tried using #import <CJDataKit/CJDataKit.h> as well but same result.
From my settings:
- "Allow Non-modular Includes In Framework Modules" is Yes on the target, and framework. It is No at the project-level.
- "Defines Module" is also set to Yes, on both the app target and framework, and No at project-level.
Would love some help in getting this setup correctly. I've been searching for a solution, but haven't really found anything.

Swift namespace in objective-c project

There is a problem with my old source code. I'm going to add new swift files to the project done with objective-c. Everything works fine except compiler asks to add Swift namespace to all types like String, Array, Void etc in swift files.
So I have to write
let foo: Swift.String
instead of simply String.
Not a big deal but why?

Swift generated header with multiple targets

I am having trouble generating the swift header needed to use Swift classes from ObjC, when there are multiple targets with common code.
I created two targets My OSX App and My iOS App. These targets share common code where an ObjC class is calling a Swift class.
As described in Swift and ObjC in the same project I can add #import "My_iOS_App-Swift.h" to my ObjC class and compile it from the My iOS App target.
However, this doesn't compile from the My OSX App target, as the include needs to match the module name. It is looking for #import "My_OSX_App-Swift.h"but the common code does not use that include.
What is the correct way to mix/match Swift/ObjC in code that is shared between multiple targets? I could manually change every target to use a common MyApp-Swift.h, but that doesn't feel right and may cause other problems.
Set the Product Module Name setting in Build Settings to be the same across your modules
For example: $(PROJECT_NAME)
Or use fixed names if you have watch extensions for different targets like: Main_App and Watchkit
This causes the ###-Swift.h file that is generated has the same name across all modules. This also eliminates the need for adding/checking preprocessor micros.
From: Objective C to Swift header file with multiple targets

Swift extension in Cocoapods Framework causing Unrecognised Selector sent to Class

I have a Swift framework which is managed via Cocoapods and contains an extension like so:
public extension UIImage {
public static func maskedImageWithColor( color: UIColor, forImageNamed image: UIImage) {
// Implementation
}
}
When I write it in Objective C in my main application I get no compiler errors or warnings.
// No problems here!
[UIImage maskedImageWithColor:UIColor.blackColor() forImageNamed:#"myImage"];
When I run the app, however, it explodes in a mess of 'Unrecognised Selector' errors.
The weird thing is, when the framework is contained within the project and added directly to the relevant parts of build phases (i.e. not managed by Cocoapods), it all works as expected.
Other aspects of the framework—classes, enums, etc.—all work fine too, it just seems to be extensions and only when they're in an framework managed by Cocoapods.
Any ideas on what I might be missing here?
This is because the linker is not loading category methods form static library by default. If you are adding category methods(extension in swift) with static library, add -ObjC to other linker flags in your targets build settings.
Read more here

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

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