17

I have a CustomViewController class written in swift and a CustomNavigationController class written in Objective C. I'm trying to add my CustomNavigationController as a property to my CustomViewController. I've added #import "CustomNavigationController.h" to my bridging header.

In my CustomViewController I have:

class CustomViewController: UIViewController {

    var navController: CustomNavigationController?
...
//init methods


...


 override func viewDidLoad() {
        super.viewDidLoad()

        //Set up Navigation Controller
        navController = self.storyboard.instantiateViewControllerWithIdentifier("CustomNavigationController") as CustomNavigationController!
}

There are no errors until I try to build and run...I get "unknown type name 'CustomNavigationController'; did you mean 'UINavigationController'?"

Does anyone know why it doesn't recognize the type?

Nick Yap
  • 887
  • 1
  • 10
  • 13
  • Which line does the error occur on? – matt Jun 07 '14 at 17:20
  • 1
    When declaring the property at the top. It runs if I declare navController as a UINavigationController and then downcast it to my CustomNavigationController in viewDidLoad, but I feel like that's a roundabout way of doing it. – Nick Yap Jun 07 '14 at 17:31
  • I tried it and it works fine for me (at least based on what you've revealed so far) – matt Jun 07 '14 at 17:44
  • Look in the build settings and make sure the Objective-C Bridging Header is pointing at your bridging header. – matt Jun 07 '14 at 17:47
  • 1
    @matt It is...But I just realized that I don't need this to be a property anyway so I just declared it in viewDidLoad. The error still doesn't make sense though – Nick Yap Jun 08 '14 at 00:31
  • In my test, I put the `var navController: CustomNavigationController?` line in as many different places as I could think of and there was no error. – matt Jun 08 '14 at 01:22
  • It might have something to do with me trying to instantiate it from the storyboard, but thats just a shot in the dark – Nick Yap Jun 08 '14 at 01:31
  • @matt: Here's an example project demonstrating the bug https://johnboiles.s3.amazonaws.com/SharedOnline/MyProject.zip – johnboiles Jun 12 '14 at 22:26
  • @johnboiles That's a great example. Couldn't be simpler! Thanks very much. You might like to put that on github where it's easier for people to see and play with. – matt Jun 12 '14 at 22:55
  • @johnboiles The real question is why I can't reproduce this in my own very simple test. Is it because I'm using a storyboard and you're not? – matt Jun 12 '14 at 23:42
  • @johnboiles Nope, it's not the storyboard. I deleted the storyboard and I still compile just fine. I don't see any difference between your project and mine, but there must be one...! – matt Jun 12 '14 at 23:52
  • @johnboiles I got it! Delete the `#import` of the bridging header from the app delegate class file and your project compiles just fine. – matt Jun 12 '14 at 23:54
  • Okay, I've summed up my conclusions in a new answer. – matt Jun 13 '14 at 00:14
  • @matt if you don't import `MyProject-Swift.h` you won't be able to use the Swift class (MyClass in the example) in Objective-C code. I'll update the example to make that more explicit. – johnboiles Jun 13 '14 at 03:07
  • Here's a more explicit version of the example project demonstrating the bug. It now explicitly uses the Swift class from Objective-C. https://johnboiles.s3.amazonaws.com/SharedOnline/MyProject2.zip – johnboiles Jun 13 '14 at 03:12

5 Answers5

24

In your Objective-C code, you are somewhere importing the automatically generated -Swift.h header. In that same code, before that #import line, insert #import "CustomNavigationController.h". The order of these two #import statements is crucial!

This will solve the problem by making sure that CustomNavigationController is in the namespace before the automatically generated -Swift.h header, and so the latter will know about the former and all will be well.

This is something of an annoyance if that Objective-C class had no need to know about CustomNavigationController, but it solves the problem going forward and allows you to continue to work with your hybrid project.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    As @johnboiles has pointed out, this is actually in the [guide](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_75). – matt Jun 14 '14 at 05:01
  • This is pointed out in the answer, but make sure you check each of the files where you have `#import X-Swift.h`. – Brian Broom Jul 07 '14 at 02:21
  • 1
    I did this, going through each OBJC file where I use Swift classes and setting my `-Swift.h` file as the last include, but it still failed with the same error :( – Ruben Martinez Jr. Jul 17 '14 at 18:03
8

Looks like the ProjectName-Swift.h generated header file doesn't automatically include the contents of ProjectName-Bridging-Header.h. This causes any types that haven't already been declared before importing ProjectName-Swift.h to throw the Unknown type name error in the compiler. This seems like a bug.

My workaround was to create an alternate version of ProjectName-Swift.h that forward declares the classes that are causing the errors, then imports ProjectName-Swifth.h. I called it ProjectName-Swift-Fixed.h. For me, ProjectName-Swift-Fixed.h looked like this:

// ProjectName-Swift-Fixed.h
@class CustomViewController;
#import "ProjectName-Swift.h"

Then, everywhere in code where I had #include "ProjectName-Swift.h", I replaced it with #include "ProjectName-Swift-Fixed.h"

johnboiles
  • 3,494
  • 1
  • 32
  • 26
  • Found another [SO post](http://stackoverflow.com/a/24132572/163827) that found a small mention of this in [Apple's ObjC - Swift Interop Guide](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_75): "If you use your own Objective-C types in your Swift code, make sure to import the Objective-C headers for those types prior to importing the Swift generated header into the Objective-C .m file you want to access the Swift code from." – johnboiles Jun 12 '14 at 23:04
  • Your demo project had a bug in it (yours, not Apple's), which I eventually found. See my new answer. – matt Jun 13 '14 at 00:15
  • I think you're misunderstanding the issue here. This only happens if you are both using Swift classes in Objective-C code and Objective-C classes in your Swift code. `ProjectName-Swift.h`, the file that tells your Objective-C code about your Swift classes, will reference the Objective-C classes that are used in Swift code. If those classes haven't already been imported, or forward-declared, the compiler will error. – johnboiles Jun 13 '14 at 19:21
  • Okay, I see. But the requirement that you import those classes first is pretty minimal and is certainly a lot easier than your workaround. For example, in your http://johnboiles.s3.amazonaws.com/SharedOnline/MyProject2.zip example, in the app delegate just say `#import "CustomViewController.h"` before you say `#import "MyProject-Swift.h"` and the problem is solved. That's a lot less onerous than your song-and-dance above... – matt Jun 14 '14 at 04:53
  • That's certainly a fine solution for projects that only `#import "MyProject-Swift.h"` once or twice. If you `#import "MyProject-Swift.h"` in more than a few places, it becomes time consuming to update your `#import`s above every place you `#import "MyProject-Swift.h"`. I prefer to do all the necessary forward declarations and and/or imports for the Swift header in one place. – johnboiles Jun 14 '14 at 20:40
5

In case you can´t fix the problem by changing the order of #import statements as suggested by the above answers, checking the files in your ProjectName-Bridging-Header.h for missing framework imports might work.

In my case, I had a class in the bridging header file that was using UIImage in one of it´s methods. When my project consisted solely of Objective-C that worked fine but when exposing this header to Swift I had to add #import <UIKit/UIKit.h> in order to remove the error.

Lucifer
  • 71
  • 1
  • 3
0

Try this:

navController = self.storyboard.instantiateViewControllerWithIdentifier("CustomNavigationController") as? CustomNavigationController
Adam
  • 26,549
  • 8
  • 62
  • 79
0

I encountered the same situation. In my case, the errors resolved after updating swift version to 3.0 in all targets by Edit > Convert > To Current Swift Syntax. Hope it helps

Justin Sato
  • 523
  • 1
  • 4
  • 20