Generated Objective-C header from Swift - ios

I have problem with generated ObjC header file (Project-Swift.h) from Swift classes.
Header file contains representation of defined Swift classes and all imports of required dependencies. Actually I combine ObjC with Swift in one project together. Everything works fine until I would like create subclass XYZTableViewController of Swift class ABCTableViewController from external framework.
Definition of class from swift file:
#objc class XYZTableViewController: ABCTableViewController { ... }
Generated content from Project-Swift.h:
SWIFT_CLASS("_TtC6Abc22XYZTableViewController")
#interface XYZTableViewController : ABCTableViewController
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)aDecoder OBJC_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER;
- (nonnull instancetype)initWithStyle:(UITableViewStyle)style OBJC_DESIGNATED_INITIALIZER;
#end
Compilation finish with this error:
Project-Swift.h:140:37: Cannot find interface declaration for 'ABCTableViewController', superclass of 'XYZTableViewController'; did you mean 'UITableViewController'?
It works if I'm importing module into .m files for the external framework and defining properties of related class type.
Does have anybody that problem or another similar complications?

You cannot subclass a Swift class in Objective-C. Taken from Using Swift with Cocoa and Objective-C.
So yes, you can use the ABCTableViewController as a #property for composition, but you cannot inherit from it.

I found problem in project structure. I don't know why, but project contains unused ObjC++ source .mm and in this situation compiler ignore project settings and also doesn't generate modules.
helpful and related page: use of #import when modules are disabled

Related

Unable to access SPM classes in Swift classes referencing Obj-C classes

I'm currently working on moving one of our apps dependencies from Cocoapods to SPM. The dependency is written purely in Swift, but our codebase using it is both ObjC and Swift.
The problem I'm running into now is that anytime a class from the SPM library is defined in an ObjC class, it works, but if Swift tries to reference the property (from the ObjC class) it throws the error message: Value of type SwiftClass has no member libraryClass.
Before moving this package into SPM, Swift files had no issue referencing ObjC definitions of the librarys' classes. Now, anywhere in the app we try to do that the compiler doesn't have access to them.
The code structure looks something along the lines of this, stripped down to keep things minimalistic.
#objc
public class LibrarySwiftClass: NSObject {
etc etc
}
#interface ObjectiveCClass
#class LibrarySwiftClass;
#property (nonatomic, strong) LocalSwiftClass *localClass;
#property (nonatomic, strong) LibrarySwiftClass *libraryClass;
#end
extension ObjectiveCClass {
#objc
func checkPropertyValue() {
let testValue1 = self.localClass <----- This works correctly with no issue
let testValue2 = self.libraryClass <----- The above error happens here
}
}
NOTE: For this example the Swift class is an extension of the Objective C class, but there are other spots in the app where the Swift class isn't related to the ObjC class and they're still failing.
I put in breakpoints to check, and upon using self.value(forKey: "objCProperty") in the swift class, it does show it correctly. Also, there are other non-SPM classes in the ObjC file that are able to properly be referenced with no issue.
I've tried including the ObjC files in the bridging header, and a couple other solutions to get the Swift file access to this property, with no luck. Seems like a very specific error case when setting up SPM. Anyone have any ideas?

Prevent Swift files from being exposed to the Objective-C Generated Interface Header

Is it possible to explicitly declare that a Swift source file isn't included in the Objective-C Generated Interface Header? As an example, let's say I have this Swift class
class MyViewController: UIViewController {
}
In my MyApp-Swift.h generated header, I see this
SWIFT_CLASS("_TtC4MyApp16MyViewController")
#interface MyViewController : UIViewController
- (nonnull instancetype)initWithNibName:(NSString * _Nullable)nibNameOrNil bundle:(NSBundle * _Nullable)nibBundleOrNil OBJC_DESIGNATED_INITIALIZER;
- (nullable instancetype)initWithCoder:(NSCoder * _Nonnull)coder OBJC_DESIGNATED_INITIALIZER;
#end
However I would prefer this class isn't exposed to Objective-C. I'm working in a larger app, and our generated -Swift.h file is well over 8,000 lines. This ends up making incremental builds painful when something that should only require a recompilation of the Swift code ends up causing a recompilation of the Objective-C code as well simply because this header file changed.
#nonobjc sadly does not work. I receive the error '#nonobjc' attribute cannot be applied to this declaration.

Swift framework - Use Swift class reference in Objective-C class

I am creating Swift framework in which I have to use Objective-C class. So I went through this link. This is the public header of my framework :
#import <UIKit/UIKit.h>
//! Project version number for Test.
FOUNDATION_EXPORT double TestVersionNumber;
//! Project version string for Test.
FOUNDATION_EXPORT const unsigned char TestVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Test/PublicHeader.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>
#import <MyTest/MPAppDelegateProxy.h>
Now in class MPAppDelegateProxy, I have to use a Swift class which I have created. This is :
#import "MPAppDelegateProxy.h"
#import "MyTest.h"
#implementation MPAppDelegateProxy
+ (void)proxyAppDelegate {
[MPGlobal MPLog:#"App delegate not set, unable to perform automatic setup." file:#"MPAppDelegateProxy.m" function:#"proxyAppDelegate" line:32];
// rest of code
}
MPGlobal is one of my Swift class. But I am getting :
Use of undeclared identifier 'MPGlobal'
Note : I have added #objC before MPGlobal.
You need to import <Target>-Swift.h file.
This is known as Objective-C Generated Interface Header Name.
You can find it in your Target's build settings.
This file is auto generated by compiler and it needs to be imported in Objective-C files.
change the SWIFT_OBJC_INTERFACE_HEADER_NAME build setting and making it the same across different targets. To do so change the instruction that generates this property from $(SWIFT_MODULE_NAME)-Swift.h to $(PROJECT_NAME)-Swift.h as explained here
After doing this Clean Build Folder by pressing Alt and going into Product menu. Since name of header is shared among targets now it can be imported once in the .m ObjectiveC file and all targets can benefit from Swift classes.
If after building it still shows the error, ensure that the header can be reached from XCode by Cmd clicking on its name. It should open a file that contains code similar to this:
SWIFT_CLASS("_TtC27ProjectName_Summary11MyClass")
#interface MyClass : NSObject
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
If need to ensure that those headers are being generated open a terminal and use this command
find ~/Library/Developer/Xcode/DerivedData -name "*Swift.h"
You should see one header for each target
Another issue that happened to me after those changes is that it started giving errors on ObjectiveC code that I didn't touch. The problem was due to the position of the import, as reported here:
Exactly where at the top of a .m file you #import the hidden bridging
header can make a difference. The usual sign of trouble is that you
get an “Unknown type name” compile error, where the unknown type is a
class declared in Objective-C. The solution is to #import the .h file
containing the declaration for the unknown type in your Objective-C
files as well, before you #import the hidden bridging header. Having
to do this can be an annoyance, especially if the Objective-C file in
question has no need to know about this class, but it resolves the
issue and allows compilation to proceed.
At the very end the code compiles and runs on device and simulator!
Original answer
Also you can try this,
You needed to import the -Swift.h for for both the framework and the app target
For Example :
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <Foundation/Foundation.h>
#import "XLPagerTabStrip-Swift.h"
#import "RealmSwift-Swift.h"
...... // Add all frameworks, subclasses, and dependance ios frameworks
#import "MyProject-Swift.h"
You can read this article How to import file header and check paths

#import ProjectName-Swift.h into header file Can't use swift as .h property?

So I'm trying to use an #objc swift class as a property on my objective-c header file.
example
#objc class SwiftClass: NSObject {
}
#interface ObjcObject : NSObject
#pragma mark - Public Properties -
#property (nonatomic, weak) SwiftClass* swiftClass;
However if I #import ProjectName-Swift.h it gives me the error that "'ProjectName-Swift.h'file not found'
I found an answer here that implies you can't actually import Swift into a header file https://stackoverflow.com/a/29951314/3877767
How then am I supposed to use swift code together with objc code? I would not call swift and objc interoperable if you can't use #objc marked swift classes as properties on and objc header file
So inside of my App-Bridging-Header.h
#import "ObjcClass.h"
and inside of my ObjcClass.h
#import "ProjectName-Swift.h"
This gives the error ProjectName-Swift.h can't find file
Either removing the #import ProjectName-Swift.h, or the #import ObjcClass.hfixes the problem, but then I can't use the Swift/OBJC code respectively
You don't import the header file. You give it to the compiler as a so-called "bridging header" that tells the compiler what to share between the two language environments.
You need to put your header file under the Objective-C Bridging Header as shown below:

Adding Linked or Embedded Swift Framework: 'MyClass' is unavailable: cannot find Swift declaration for this class

I have a Swift Cocoa Touch Framework project (we'll call it MySwiftFramework) that has some nifty code in it that I'd like to reference in another project/workspace.
When attempting to reference that framework, I get the following error in the code that references the swift classes of the aforementioned framework:
'MySwiftClass' is unavailable: cannot find Swift declaration for this class
I've checked the auto-generated file: MySwiftFramework.framework/Headers/MySwiftFramework-Swift.h and it includes the auto-generated headers for the swift classes in MySwiftFramework:
SWIFT_CLASS("_TtC16MySwiftFramework12MySwiftClass")
#interface MySwiftClass : NSObject
#property (nonatomic, copy) NSString * coolThingName;
- (instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
The only way I can get it to work is if I drag MySwiftFramework into the workspace I'm trying to reference it with. Then it will compile, but when I try to archive the app, it archives the project as "Xcode Generic Archive" instead of an "iOS App Archive".
There's got to be a way to reference a swift framework by just embedding the MySwiftFramework.framework file.
Does anyone know what might be causing this error?

Resources