objective-c - Swift classes are not visible in Objective-C .h file - objective-c

I'm trying to use Swift class in my Objective-C file.
I included "moduleName-Swift.h" file in my SuperViewController.m file, but when I try to declare a public method in SuperViewController.h with Swift-class as method parameter, I obviously get an error: "Expected a type"
How can I use swift-class in a header file if I can only include projectModule-Swift.h in .m files??

Make sure to put #objc before the swift class name.
#objc myclassname { ... }
Also add
#class myclassname;
in your obj-c header file where you want to access the swift class

Remember to import the project generated swift header file in your source file, for example #import <MyProjectName-Swift.h>

I had the same problem. Adding #class MyClassName in obj-c .h file created the "Receiver 'MyClassName' for class message is a forward declaration" error, so I deleted that and ONLY added the "#objc" before the swift class name, BUT I also had to make sure that the swift class is a subclass of NSObject.
#objc class MySwiftClass:NSObject { ... }
WITHOUT #class MyClassName in obj-c .h file!

I had to use:
#obj public class MySwiftClass: NSObject { ... }

I created a class with no subclass, adding #objc and #objcmembers did not work.
After I change do :NSObject the entire class turn visible to objective-C

Related

Unable to call some methods from an Objective-C class in a Swift extension of that class

I have an objective-c class something like:
#interface MyClass: NSObject { }
- (MyObject *)coolMethod;
#end
#implementation MyClass
- (MyObject *)coolMethod {
return [self doCoolStuff];
}
#end
...and a Swift extension something like:
extension MyClass {
#objc func addedMethodInSwift() {
let coolObj = coolMethod() // <<<< compiler error - method not found
}
}
The code will not compile, because the compiler cannot find the implementation of coolMethod(), however certain other methods from the Objective-C class can be called from the Swift extension.
I have checked and the Objective-C header file is included in the project's bridging header, so it should be visible to Swift. The method in question is definitely visible in the header file.
Why can't coolMethod() be called from the Swift extension?
Check that both your objective-C class and the return type of the function (in your case MyObject.h) are included in the Bridging header. Methods with return types not included in the bridging header are not available from Swift.

getting Swift Object from Objective C class using another Swift File

I have been trying with no success the following structure:
ClassA.swift
class ClassA:NSObject{
var varA = ""
}
then I have a ClassB.h and ClassB.m (Objective c) and I am not able to define "Project-Swift.h" in the .h file so i import it into the .m
#interface ClassB()
#property ClassA *myClassA;
#end
and
#synthesize myClassA = theAClass;
The problem comes when I try
class ClassC:NSObject{
let theClassAFromC = ClassB.myAClass
}
I get an error message Value of type 'ClassB' has no member 'theClassA'
Add your objc header to bridging header
In your objc header use #class notation for your swift class, e.g. #class ClassA;, instead of import "Project-Swift.h" file. You can import that one in your objc implementation file.
Don't forget that you cannot access non-static property of objc class the way you're declaring. Instead, initialize your ClassB object in your swift class and access it's property when needed. For instantiating the ClassA object you can use dependency injection in ClassB
As part of the convenience, use #objc declaration for your Swift classes accesible to objc runtime
try to search with keyword "Bridging-Header" and then add
#import "ClassB.h"
That does not work in my case.
adding ClassB.h in my Bridge File makes properties from .h Visible But not the the properties in my .m file. If i add Class.m In my header file then Module-Swift.h is not found

Swift class in Objective C Project

I'm having problems executing some Swift code in an existing ObjC project. This is my first attempt at Swift so I'm sure I'm missing something simple.
I have added my new swift file to my project - this process generated the bridging header. So now I have the following:
bridging-header file
//
// Use this file to import your target's public headers
// that you would like to expose to Swift.
//
#import "historyViewController.h"
In my swift file I have the following test class and function:
import Foundation
#objc class Hello: NSObject {
func sayHello() {
print("Hi There")
}
}
In my historyViewController.m file I have the following
#import "xx-Bridging-Header.h"
In my historyViewController.h file I have the following
#class Hello;
How do I actually go about executing the sayHello function from within my historyViewController.m file? I've tried [Hello sayHello]; - but get 'no known class method'.
The problem is only that you are calling sayHello as if it were a class method, but sayHello is declared as an instance method. So:
[[Hello new] sayHello];

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 protocol in Objective-C class

I wrote SearcherProtocol in Swift and need to implement an Objective-C class FileSearcher which has to use this protocol.
So I tried this:
#import <Foundation/Foundation.h>
#interface FileSearcher : NSObject <SearcherProtocol>
// ... class content
#end
The compiler tells me
Cannot find protocol declaration for 'SearcherProtocol'
The corresponding bridged header file (modulename-Swift.h) is being imported within FileSearcher.m.
Importing SearcherProtocol into FileSearcher.h throws another compiler error: module name-swift.h file not found
Does anybody have any clue what I'm doing wrong?
I'm using Xcode 6 Beta 5.
Edit
Here is the protocol declaration in Swift:
#objc protocol SearcherProtocol
{
var searchNotificationTarget: SearchCompletedProtocol? { get }
var lastSearchResults: [AnyObject] { get set }
func search(searchParam: String, error: NSErrorPointer) -> Bool
}
And the SearchCompletedProtocol:
#objc protocol SearchCompletedProtocol
{
func searchCompletedNotification(sender: AnyObject!)
}
There are two common reasons for this occuring:
Getting the module name wrong, see my answer.
Having a circular reference - see mitrenegades answer below.
1. Get the module name right:
If both the swift protocol and and Objective C are in the same project then according to apple you should just need to make sure you get the correct module name.
For Xcode6 beta 5 you can find it under BuildSettings->Packaging->Product Module Name
A common mistake would be to think that each swift file/class gets its own file, but instead they are all put into one big one that is the name of the project.
A further mistakes are if the module name has spaces, these should be replaced with underscores.
Edit:
With your protocol I created a test project called 'Test' which compiles perfectly and it has the files:
TestObjClass.h
#import <Foundation/Foundation.h>
#import "Test-Swift.h"
#interface TestObjCClass : NSObject <SearcherProtocol>
#end
TestObjClass.m
#import "TestObjCClass.h"
#implementation TestObjCClass
#end
TestProtocol.swift
import Foundation
#objc protocol SearcherProtocol
{
var searchNotificationTarget: SearchCompletedProtocol? { get }
var lastSearchResults: [AnyObject] { get set }
func search(searchParam: String, error: NSErrorPointer) -> Bool
}
#objc protocol SearchCompletedProtocol
{
func searchCompletedNotification(sender: AnyObject!)
}
2. Avoid circular reference:
Mitrenegades answer explains this, but if your project needs to use the explicit objc class that uses the swift protocol, (rather than just using the protocol) then you will have circularity issues. The reason is that the swift protocol is defined to the swift-objc header, then to your obj-c class definition, which then goes again to the swift-objc header.
Mitrenegades solution is to use an objective-c protocol, is one way, but if you want a swift protocol, then the other would be to refactor the code so as to not use the objective-c class directly, but instead use the protocol (e.g. some protocol based factory pattern). Either way may be appropriate for your purposes.
When you have
#import "moduleName-Swift.h"
in the .h file that you want to be a delegate, and you have that .h file also in the bridging headers file, there's a circular reference that causes the moduleName-Swift.h to fail compilation. for #james_alvarez's test project, it's probably working because you don't need to include TestObjClass.h into the bridging header.
The best way for me to combine objc files that need to be the delegate for a class written in swift, but that also needs to be included in the bridging header so other swift files can access this objc class, is to create a separate protocol file in objc:
MyProtocol.h:
#protocol MyDelegate <NSObject>
-(void)didDoThis;
-(void)didDoThat;
#end
ViewController.h:
#import "MyProtocol.h"
#interface ViewController : UIViewController <MyDelegate>
MyProject-Bridging-Header.h
#import "MyProtocol.h"
#import "ViewController.h"
I know this was a long time ago, but I just struggled with the same problem when adding a protocol to my Swift code, and it wasn't being added to the -Swift.h header file, hence "Cannot find protocol declaration"
The problem was my protocol wasn't marked as Public. I changed my protocol from this:
#objc protocol MyProtocol { //etc.... }
to this:
#objc public protocol MyProtocol { //etc.... }
I'm still not entirely sure why I need 'Public' but nobody else seems to, but hey it works...
Make sure you are including the auto generated Swift header in your ObjectiveC file. It will have the same name as your project module followed by -Swift.h.
For instance if your Project Module is MyTarget, then you would use:
#import "MyTarget-Swift.h"
If you are typing in the import into your Objective C file, it will not autocomplete. You can verify that you have the correct file by Command-clicking on the header after typing it in.
You can do the conformance part from Swift side 😁
So you have a swift protocol and want to make an Objective-C type conforms to it,
Swift Side
Add #objc to your protocol to make it visible to Objective-C world.
#objc protocol IndianCooking {
func cookChicken()
}
Objective-C Side
In the implementation .m file you do the following:
#import "YourProject-Swift.h"
#interface Cheef ()<IndianCooking> {
}
and in the header file .h add the method
cookChicken()
Import delegate as like this in .h file
#protocol AnalyticProtocol;
and add this in to .swift file
#objc public protocol AnalyticProtocol {
}
Try adding #import "Product_Module_Name-Swift.h" to your Product_Module_Name-Prefix.pch file. That fixed it for me, plus you will now have access to your swift files from any objc file.