"ProductModuleName-Swift.h" not exporting all Swift classes - objective-c

I have defined two Swift classes in my Xcode project. Everything else is Objective-C.
To use the classes in Objective-C I'm trying to import ProductModuleName-Swift.h but the file contains only the definition for one of the Swift classes. (SearchViewController)
This class is being exported:
class SearchViewController : UIViewController {
but this isn't:
public class Socket {

From "Migrating Your Objective-C Code to Swift" in the "Using Swift with Cocoa and Objective-C" documentation:
To be accessible and usable in Objective-C, a Swift class must be a descendant of an Objective-C class or it must be marked #objc.
When you bring Swift code into Objective-C, remember that Objective-C won’t be able to translate certain features that are
specific to Swift. For a list, see "Using Swift from
Objective-C".
SearchViewController is a descendent of an Objective-C class, but Socket is not.
To make it usable in Objective-C, declare it as a subclass of NSObject:
public class Socket : NSObject { ...
or declare it as
#objc public class Socket { ...

Related

Obj-C classes inheriting from Swift classes cannot be used by Swift code?

I have a class that is defined in Swift:
// SwiftClass.swift
#objc
class SwiftClass: NSObject {
// ...
}
An Objective-C class can inherit from that Swift class:
// ObjCObject.h
#import "MyModule-Swift.h"
#interface ObjCObject: SwiftClass
// ...
#end
However, when doing so, I cannot use that class in Swift code anymore.
To use it in Swift, I have to add it to the bridging header:
// MyModule-BridgingHeader.h
#import "ObjCObject.h"
as only classes referenced by the bridging header are visible to Swift code. And this creates a cyclic reference, as the bridging header must be processed prior to compiling the Swift source code yet the generated Swift header (MyModule-Swift.h) only exists after compiling the Swift source code and thus won't exist when the bridging header is being processed.
If it was just for method arguments, I could use forward declarations but an Obj-C class cannot inherit from a forward declared class.
So am I just missing something here or is it really the case that you can use Obj-C classes in Swift and Swift classes in Obj-C but you cannot use an Obj-C class in Swift if it inherits from a Swift class?

how to exclude classes from <MyProject>-swift.h

I have a project that was started in Objective-C, and I am trying to import some Swift code into the same class files that I have previously written Objective-C in.
I need exclude Swift classes from <MyProject>-swift.h
for example exclude LoginVC
Only the swift class with #objc will generate objective-c interface in Project-swift.h.
By adding #objc, your swift class will be visible by others objective-c class.
Example :
#objc class LoginVC : UIViewController{ //will be present in Project-swift.h
class LoginVC : UIViewController{ //will not be present in Project-swift.h

Writing Swift 2.0 code inside Objc *.m file

I'm trying to use a swift classes methods from my objective-c .m file but I can't get my file to import.
In Build Settings -> Packaging I have: Defines Module YES
my Product Module Name is Library
In Build Options I have set Embedded Content Contains Swift Code as YES
However, when I attempt to import the target module to my *.m file I get file not found error.
#import "Library-Swift.h"
Fails to import.
I have swift files. Any ideas?
I'm also trying to use `"Library-Bridging-Header.h"
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "PLAddBookViewController.h"
..but it doesn't seem to be doing anything.
You can expose your Swift class to ObjC in 2 ways:
class MySwiftClass : NSObject { // inherit from any ObjC class
}
#objc class MyClassClass { // tell the compiler to expose it to ObjC
}
From the Swift book:
When you define a Swift class that inherits from NSObject or any other Objective-C class, the class is automatically compatible with Objective-C. If your Swift class does not derive from an Objective-C class and you want to use an API from that class in Objective-C code, you can use the #objc attribute described below.
The #objc attribute makes your Swift API available in Objective-C and the Objective-C runtime. In other words, you can use the #objc attribute before a Swift method, property, subscript, initializer, class, protocol, or enumeration to use it from Objective-C code.

Swift and Objective-C Classes With the Same Name

I am still learning how to integrate Swift code into code written in Objective C. Let's say if I name the Swift file and class the same name which already was taken by any class of Objective-C. For example,
I would create: "ViewController.swift", and have the following content:
import Foundation
import UIKit
#objc class ViewController:UIViewController {
func swiftMethod() {
print("It works.")
}
}
There are already "ViewController.h" and "ViewController.m". And later I would try to call the Swift class in Objective-C:
#import <myproject-Swift.h>
...
ViewController *vc = [ViewController new];
[vc swiftMethod];
...
How the compiler would know which class I initiated: the class from Swift or from Objective-C?
In the Obj-C runtime, the two classes actually have different names. The Swift class is named YourProject.ViewController while the Obj-C class is named simply ViewController.
From Obj-C code, which class you get will depend on which header you import.
If you import both headers then it's a compiler error.
If you force both classes to have the same name, using:
#objc(ViewController) class ViewController: UIViewController {
}
then it's a linker error.

Can Objective-C code call Swift class extensions?

I searched some posts, I think I cannot write an extension under Swift, and call it from Objective-C code, right?
#objc like attributes only support methods, class, protocols ?
You can write a Swift extension and use it in Objective-C code. Tested with Xcode 6.1.1.
All you need to do is:
create your extension in Swift (#objc annotation needed since Swift 4.0.3)
#import "ProjectTarget-Swift.h" in your Objective-C class (where "ProjectTarget" represents the XCode target the Swift extension is associated with)
call the methods from the Swift extension
I found out that in Swift 4.0 I had to add #objc in front of my extension keyword in order for the Swift extension methods to become visible by an instance of the Objc class I was extending.
In short:
File configuration setup:
CustomClass.h
CustomClass.m
CustomClassExtension.swift
In CustomClassExtension:
#objc extension CustomClass
{
func method1()
{
...
}
}
In my AppDelegate.m:
self.customClass = [[CustomClass alloc] init];
[self.customClass method1];
This solution works for Swift 2.2 and Swift 3. Note that only extensions for classes (not for structs or enums) will be accessible from Objective-C.
import UIKit
extension UIColor {
//Custom colours
class func otherEventColor() -> UIColor {
return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
}
}
Then #import "ProductModuleName-Swift.h" in your ObjC file.
Swift 4
extension UIColor {
// As of Swift 4.0.3, the #objc annotation is needed if you want to use the extension in Objective-C files
#objc
class func otherEventColor() -> UIColor {
return UIColor(red:0.525, green:0.49, blue:0.929, alpha:1)
}
}
As covered in the other answers, importing the generated Swift header works in most cases.
An exception to this is when the category is defined on a bridged type (i.e. the extension is defined on String and not NSString). These categories will not automatically be bridged to their Objective-C counterparts. To get around this, you'll either need to use the Objective-C type (and cast the return value in your Swift code with as String) or define an extension for both the Swift and Objective-C types.
Import "#import "ProductModuleName-Swift.h" header in objective-c file and add #objc infront of your extentsion in swift file. It will working fine in swift 4.2 and swift 5
If think you have configured everything correctly (marked your Swift entities with #objcMembers or #objc, imported the bridging header "ProductModuleName-Swift.h" and so on) – but still getting the No visible #interface for 'FooClass' declares the selector 'fooSelector' error:
Check if you see your interfaces in the bridging header by ctrl + cmd clicking on it. If you don't, check out my answer to this question: Swift to Objective-C header does not contain Swift classes