In a Swift project that has mixed Obj-C and C++, I have a class that extends the class belonging to a 3rd party framework. When I compile the project, the compiler complains that it Cannot find interface declaration for '<Framework Class Name>', superclass of '<My Subclass Name>'
The semantic error points to the auto-generated bridging header ('MyProjectName-Swift.h').
Is there a way to not have a particular class included in the bridging header besides marking it private or fileprivate? (Which makes the subclass not much use in the rest of the project..) I've looked through the Apple docs on this matter and there doesn't seem to be any specific direction on this.
Alternatively, any clues as to how to fix this? The header includes this bit:
#if __has_feature(modules)
#import UIKit;
#import Material;
#import CoreGraphics;
#import ObjectiveC;
#endif
Which seems like it should make the proper reference to the superclass (in this case, if it matters, Material.PresenterCard) But — I'm pretty sure this pre-compiler directive isn't being referred to as I've heard of a related bug.
I recently had a very similar problem and solved it by defining an empty Objective-C class for the case where modules weren't available.
My situation was App -> Framework -> Package (Swift Package)
Framework implemented DerivedClass, which subclassed BaseClass defined in Package
When importing Framework-Swift.h internally or externally within any Objective-C++ code, the compiler would complain that BaseClass could not be found in the generated header
I solved this by adding the following code to Framework's umbrella include (Framework.h):
#if !__has_feature(modules)
#interface BaseClass: NSObject
#end
#endif
So when modules are unavailable (Objective-C++), BaseClass is defined as an empty Objective-C class. This allowed the framework to be imported into Objective-C++ code to use other features of the framework
Related
I am building a Mac OS X app (binary). Skit is the Swift framework, and Pal is the Application which contains the .m file. The compiler cannot find NSArray or NSDictionary, which means that the compiler can't find the Foundation module. If I go to the error in Pal-Swift.h (which is generated) and add the #import Foundation or #import Cocoa manually, the binary compiles fine and I am able to use the classes in the framework from objc as expected, and I can typically keep iterating until I need to do a clean build.
The error looks like this.
While building module 'SKit' imported from /Users/mtozer/Library/Developer/Xcode/DerivedData/Pal-dznqzplhixgqpgduvvxjqiknvhrr/Build/Intermediates/Pal.build/Debug/Pal.build/DerivedSources/Pal-Swift.h:90:
In file included from <module-includes>:1:
/Users/mtozer/Library/Developer/Xcode/DerivedData/Pal-dznqzplhixgqpgduvvxjqiknvhrr/Build/Products/Debug/SPluginKit.framework/Headers/SKit-Swift.h:97:26: error: expected a type
- (void)executeCommands:(NSArray * __nonnull)commands;
^
/Users/mtozer/Library/Developer/Xcode/DerivedData/Pal-dznqzplhixgqpgduvvxjqiknvhrr/Build/Products/Debug/SKit.framework/Headers/SKit-Swift.h:115:4: error: expected a type
+ (NSDictionary<NSString *, id <SPlugin>> * __nonnull)loadPluginsInDirectory:(NSString * __nonnull)directory sAPI:(id <SAPI> __nonnull)sAPI;
^
2 errors generated.
In file included from /Users/mtozer/Pal/Pal/AppDelegate.m:43:
/Users/mtozer/Library/Developer/Xcode/DerivedData/Pal-dznqzplhixgqpgduvvxjqiknvhrr/Build/Intermediates/Pal.build/Debug/Pal.build/DerivedSources/Pal-Swift.h:90:9: fatal error: could not build module 'SKit'
#import SKit;
~~~~~~~^~~~~~~~~~~~~~~~~~
3 errors generated.
I'm fairly convinced this is a compiler bug, but then again I am using BUCK which does not officially support swift.
Simply putting an empty extension in my Framework's source code caused the generator to put the foundation dependency correctly in the header
extension NSArray {
}
Remember to prepend #objc to the classes and protocols declaration in Swift.
#objc public class YourClassName: NSObject { ... }
#objc public protocol YourProtocolName { ... }
If the problem persists then try appending : class at the end of the protocols used as Swift protocols can be implemented not only by classes as happens in Objc.
#objc public protocol YourProtocolName: class { ... }
I'm trying to import SKTUtils - which is a set of swift files - into an Objective-C project. As far as I know it would be enough to do this way:
#import "ProjectName-Swift.h"
But the problem is that SKTUtils is not a project, but rather a directory with a set of swift classes. I tried to import the files this way:
#import "Vector3-Swift.h"
#import "CGFloat+Extensions-Swift.h"
.... etcetera ....
But without success. I've also set to yes the define modules option inside the project's build setting but still nothing to do.
I have just tried to import SKTUtils in blank Objective-C Xcode project.
Looks like you are missing the following part of requirement for correct bridging:
You need to import ProjectName-Swift.h. Note that it's the project name - the other answers make the mistake of using the class name.
This single file is an autogenerated header that defines Objective-C interfaces for all Swift classes in your project that are either annotated #objc or inherit from NSObject.
taken from How to import Swift code to Objective-C.
For example in my test project my Project-Swift.h does contain imports of SKTUtils's extensions of SKAction because they are Objective-C-based classes of SpriteKit but some other stuff is not Objective-C friendly that's why you cannot access it because it is just not generated in -Swift.h file.
Another example is that I start seeing SKTAudio class in my Objective-C code if I make it a subclass of NSObject:
#objc public class SKTAudio: NSObject {
I have a project with Swift and Objective-C code. In my current project I have the problem that the #import "Project-Swift.h" file does not refresh if I add new Swift modules.
#import "Project-Swift.h" // does not refresh if I add .swift files
So in the Objective-C universe, the swift code is not available. the files exists, but does only contains default #defines etc. No project related stuff.
Clear Cache, rebuild, delete Derived Data does not help.
Solved it. Forgot #objc(<class>). It is mandatory.
Details here (Migrating)
Migrating Objective-C Code to Swift
And here (Swift Type Compatibility)
Interacting with Objective-C APIs
In my case it worked by building for the other target I had on my project:
Check you have prefixed your class with #objc
Choose the other scheme (target)
Build || Run
The bridging file updates
Change the scheme back to the target I was working on
Just use #objc before Swift Class that you want to use in Object-C code then Build the project.
For example:
#objc class Person : NSObject
{
// Swfit code goes here.
}
Now #import "Project-Swift.h" will be available in you project to use.
I'm integrating Swift code into a large Objective-C project, but I'm running into problems when my Swift code refers to Objective-C classes. For example, suppose I have:
An Objective-C class called MyTableViewController
An Objective-C class called DeletionWorkflow
I declared a Swift class as follows:
class DeletionVC: MyTableViewController {
let deleteWorkflow: DeletionWorkflow
...
}
If I now try to use this class by importing ProjectName-Swift.h into Objective-C code, I get undefined symbol errors for both MyTableViewController and DeletionWorkflow.
I can fix the problem in that individual source file by importing DeletionWorkflow.h and MyTableViewController.h before I import ProjectName-Swift.h but this doesn't scale up to a large project where I want my Swift and Objective-C to interact often.
Is there a way to add forward class references to ProjectName-Swift.h so that these errors don't occur when I try to use Swift classes from Objective-C code in my app?
You can create another header file that forward declares or imports the necessary classes, and then imports ProjectName-Swift.h. For example, create a file named ProjectName-Swift-Fixed.h with the contents:
// ProjectName-Swift-Fixed.h
// Forward declarations for property classes
#class DeletionWorkflow;
// Imports for superclasses
#import "MyTableViewController.h";
#import "ProjectName-Swift.h"
Then, instead of #import "ProjectName-Swift.h" in your codebase, use #import "ProjectName-Swift-Fixed.h.
This is a little silly, but it sounds like your "workaround" is what Apple intended, at least for now. From the interoperability guide:
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.
In this devforums thread, someone mentioned they already filed a bug in Radar. You probably should too.
I have an objc program and i would like to use a widget that is written in objc++ (namely https://launchpad.net/scintilla-cocoa). How do i go about this? Basically i want a new window controller object to interface with this objc++ library to define a scintilla text editor widget. Simply creating a new 'objc class' and accessing the library from there generates a bunch of errors related to the C++ class keyword and so on.
Thanks in advance
Since I'm the one who put you into the (hopefully rewarding :-)) trouble of using Scintilla, here I am.
Let's say we create a ScintillaView subclass, named ppScintillaEditor.
The file should have an .mm extension (e.g. ppScintillaEditor.mm)
The code would be roughly like this...
Interface
#import "Scintilla/ScintillaView.h"
#interface ppScintillaEditor : ScintillaView
{
// your iVars
}
// your properties / methods / whatever
Now, as for the implementation part, remember to put some initialization method to set up the view properly (as in the example accompanying Scintilla-cocoa; I mean the Test project)
Sidenote : Of course, you can create subclasses, categories or whatever on top the ScintillaView class, pretty much based on what you need - I, for example, have create a separate Category just in order to group there some ScintillaView specific commands (sooner or later, you'll notice that for some more advanced Scintilla manipulations, although it's there, it may need some polishing to be a bit more cocoa-friendly, so here you go...)
Now, last but not least...
To resolve the "bunch of errors related to the C++ class keyword and so on", as I've shown in my other video-response to your comment, all you have to do is :
Go to your project's Build Settings
Under Apple LLVM Compiler 3.0 - Preprocessing
Option Preprocessor Macros
Add to both Debug and Release :
SCI_NAMESPACE SCI_LEXER
And that's it. :-)
Hint : The above are defined by Scintilla to avoid clashes between C and non-C elements, like above... so, all it takes is to notify the preprocessor and the rest is taken care of....
you would create an objc class which has the interface your app needs, then implement and add the ivars and implement -- all behind a compilation firewall so the objc++ sources are not included in the header. your implementation would provide any necessary conversions.
it is like you have already done, but you remove the scintilla headers from the header for your wrapper -- they are visible only to your wrapper's implementation.
Update
To illustrate one possible approach:
MONScintillaWrapper.h
// no c++/scintilla sources should be included in this header
#import <Foundation/Foundation.h>
#interface MONScintillaWrapper : NSObject
- (void)setBackgroundColor:(NSColor *)pColor;
#end
MONScintillaWrapper.mm
#import "MONScintillaWrapper.h"
#implementation MONScintillaWrapper
{
scintilla::t_thing scintillaThing;
}
- (void)setBackgroundColor:(NSColor *)pColor
{
...convert pColor to a scintilla color and pass that to scintillaThing...
}
#end