can't access swift method from objective-c interface - objective-c

I need to call my swift method from an Objective-C interface, however I keep getting Use of undeclared identifier 'MySwiftClass'.
My swift class works fine on other places. I have #import "myApp-Swift.h" in my objc file and #objc before my swift class. I am not really good with Objective-C, so any help would be really appreciated.
#interface myInterface ()
-(void) logger:(NSArray<MyArray*>*) events withCallback:(void (^)(NSError*)) callback;
#end
#implementation myInterface
-(void) logger:(NSArray<MyArray*>*) events withCallback:(void (^)(NSError*)) callback{
..
[MySwiftClass mySwiftMethod]
..
}
#end
My swift class:
import Foundation
#objcMembers
public class MySwiftClass: NSObject {
#objc
class func mySwiftMethod(){
}
}

Related

Unable to call an Objective C class delegate from a Swift class

My issue here is that I need the "protocolMethod" in the OldViewController.m to be called from the NewViewController.swift in a delegate fashion.
The project I'm working on was completely written in Objective C, and there's a new View Controller that was written in Swift.
The new View Controller is supposed to call a delegate method, conformed by the Objective C caller object, so the Objective C View Controller can process that call.
The app runs and the delegate is called from Swift, but never actually executed in the Objective C View Controller.
I've tried including all the sample files and the code that's supposed to be called, so here it is:
MyProtocol.h
#import <Foundation/Foundation.h>
#protocol MyProtocol <NSObject>
- (void)protocolMethod:(NSString*)input;
#end
My-Bridging-Header.h
#ifndef My_Bridging_Header_h
#define My_Bridging_Header_h
#import <UIKit/UIKit.h>
#import "OldViewController.h"
#import "MyProtocol.h"
#endif
OldViewController.h
#import <UIKit/UIKit.h>
#interface OldViewController : UIViewController
#end
OldViewController.m
#interface OldViewController ()<MyProtocol>
#end
#implementation OldViewController
//THIS IS THE PROBLEM: NEVER GETS CALLED
- (void)protocolMethod:(NSString *)input {
NSLog(#"protocolMethod:%#", input);
}
- (IBAction)myButtonClicked:(UIButton *)sender {
NewViewController *newViewController =[self.storyboard instantiateViewControllerWithIdentifier:#"NewViewController"];
[newViewController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentViewController:newViewController animated:YES completion:nil];
}
#end
NewViewController.swift
import UIKit
class NewViewController: UIViewController {
#objc weak var myProtocol: MyProtocol?
override func viewWillAppear(_ animated: Bool) {
self.myProtocol?.protocolMethod("testing 123")
}
}
Thank you for your help!
Call a objective-C protocol method in Objective-C class from Swift
define the protocol in Objective-c MyProtocol.h
#ifndef MyProtocol_h
#define MyProtocol_h
#import <Foundation/Foundation.h>
#protocol MyProtocol <NSObject>
#optional
- (void)protoMethod:(NSString *)input;
#end
#endif
define interface of LoginViewController.h
#import <UIKit/UIKit.h>
#import "MyProtocol.h"
#class NewViewController; //declare knowledge of swift class
#interface LoginViewController : UIViewController <MyProtocol>
// method to trigger testing manual
-(void)haveFun;
#end
define implementation of LoginViewController.m
#import "LoginViewController.h"
#import "YourProductModulName-Swift.h" // will bridge exposed swift class to objc
#implementation LoginViewController
-(void)protoMethod:(NSString*)input {
NSLog(#"protocolMethod:%#", input);
}
- (void)haveFun {
// did not use the storyboard to make testing simple
// this is an #objc exposed swift class
NewViewController *newViewController = [[NewViewController alloc] init];
// now trigger predefined method that checks for protocol
[newViewController fun:self];
}
#end
now let us write a swift class that is subclassing an NSObject, here UIViewController and expose it to objc
import Foundation
import UIKit
#objc //expose class when you need to use it from Objective-C
class NewViewController: UIViewController {
// as objc bridging is working with NSObjects,
// we can use it instead of Any, which can't be exposed.
#objc(foo) weak var foo : NSObject?
override func viewWillAppear(_ animated: Bool) {
// question was: how to call (id<MyProtocol>)-(void)protoMethod:
// as we dont use storyboard for testing here..
// nothing in here
}
// no autonaming, defined -(void)fun: instead
#objc(fun:) func fun(protocolObj: MyProtocol) {
let bar = protocolObj
bar.protoMethod!("direct invokation of protoMethod")
// ah why not, lets remember the object for later.
foo = bar as? NSObject
testme()
}
#objc func testme() {
// as foo is NSObject here, check if exist
if (foo != nil) {
// cast foo and check for protocol
if let loginview = foo as? MyProtocol {
loginview.protoMethod!("PROTOCOL-LOL!")
} else {
print("i will allways love youuu!")
}
}
}
}
now lets have some fun and use the back and forth bridged stuff.
This will allocate a Objective-c class LoginViewController following <MyProtocol> and invoke -(void)haveFun method. This method will allocate a Swift Class NewViewController (important! based on NSObject) that will invoke #objc exposed swift func fun: and give self as parameter that must follow the MyProtocol. It will then invoke the protocol method of LoginViewController with a parameter NSString and store the LoginViewController object in weak var foo as NSObject. Then it will trigger internal swift testme() and use the stored foo to check again if it exists and conforms to protocol MyProtocol and invokes the protocolMethod -(void)protoMethod:(NSString*)string; again or print something if not conforming.
LoginViewController *login = [[LoginViewController alloc] init];
[login haveFun];
Don't forget the example here needs Swift bridging to Objective-C and Objective-C bridging to Swift. If that is a perfect design pattern is another talk.

Swift functions are not included into autogenerated -Swift.h umbrella file

I'm trying to access Swift class methods from Objective-C, following this guide
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
This is my Swift class:
import Foundation
#objc public class MySwiftClass: NSObject {
// modifiers public, open do not help
func Hello()->String {
return "Swift says hello!";
}
}
And here is an excerpt from the autogenerated "umbrella" file MyProductModuleName-Swift.h
SWIFT_CLASS("_TtC25_MyProductModuleName12MySwiftClass")
#interface MySwiftClass : NSObject
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
#end
It seems like XCode completely ignores methods of MySwiftClass, and as a result I can't access them from Objective-C. Xcode version is 9.2.
Is it a bug or I missed anything?
You need to add #objc before each function you want to access from Objective-C:
#objc public class MySwiftClass: NSObject {
// modifiers public, open do not help
#objc func Hello() -> String {
return "Swift says hello!";
}
}

Swift class not conforming to Objective C Protocol

I have this objective c protocol as mentioned below:
#protocol Class1<NSObject>
- (void)searchBy:(Enum1)searchType;
#end
And i am trying to make a swift class conform to that protocol . The stub which Xcode generated for me is as follows:
func search(by searchType: Enum1) {
}
But Xcode gives me an error while building that the class still doesn’t conform to protocol. What am i missing here?
Do you have your Objective-C header that contains the protocol and enum in the bridging header for swift to find?
So I created a new test app, and the view controller looks as follows:
import UIKit
class ViewController: UIViewController, Class1
{
func search(by searchType: Enum1) {
print("it works")
}
override func viewDidLoad() {
super.viewDidLoad()
let class1 = self as Class1
class1.search(by: Enum1.PlayerStateOff)
}
}
And my objective-C bridging header looks like this:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "Foo.h"
And the ObjectiveC header Foo.h looks like this:
#import <Foundation/Foundation.h>
typedef NS_ENUM(NSInteger, Enum1) {
PlayerStateOff,
PlayerStatePlaying,
PlayerStatePaused
};
#protocol Class1<NSObject>
- (void)searchBy:(Enum1)searchType;
#end
#interface Foo : NSObject
#end
And it all compiles, runs, and prints "it works" just fine in Xcode 9.2. So it's probably your bridging header, but double-check everything you're doing against the above.

Can not find Swift Protocol declaration in Obj-C class

I have created on Class in Swift and that class and its protocol I am using in Obj-C enabled project but I am getting below error while compiling my project.
cannot find protocol declaration for 'SpeechRecognizerDelegate'; did
you mean 'SFSpeechRecognizerDelegate'?
Can anyone guide me on this how can I use Swift class protocol in my Obj-C class.
Here is my Swift code:
protocol SpeechRecognizerDelegate : class {
func speechRecognitionFinished(_ transcription:String)
func speechRecognitionError(_ error:Error)
}
class SpeechRecognizer: NSObject, SFSpeechRecognizerDelegate {
open weak var delegate: SpeechRecognizerDelegate?
}
Protocol use in Obj-C:
#import "ARBot-Swift.h"
#interface ChatScreenViewController : JSQMessagesViewController <SpeechRecognizerDelegate>
Let me know if required more info.
Thanks in Advance.
in Swift:
#objc public protocol YOURSwiftDelegate {
func viewReceiptPhoto()
func amountPicked(selected: Int)
}
class YourClass: NSObject {
weak var delegat: YOURSwiftDelegate?
}
in Objective-C headerFile.h
#protocol YOURSwiftDelegate;
#interface YOURController : UIViewController < YOURSwiftDelegate >
in Objective-C Implementation.m
SwiftObject * swiftObject = [SwiftObject alloc] init];
swiftObject.delegate = self
Define your Swift protocol like this inside your Swift file.
#objc protocol SpeechRecognizerDelegate: class{
func speechRecognitionFinished(_ transcription:String)
func speechRecognitionError(_ error:Error)
}
Create a Swift Module inside your project setting then use it. You can find here complete blog for the mix language coding.
Then use Protocol inside Objective C class,
We required to add protocol inside Objective C file -
#import "ARBot-Swift.h"
#interface ChatScreenViewController : JSQMessagesViewController <SpeechRecognizerDelegate>
Then you need to conform to the protocol methods -
- (void)viewDidLoad {
[super viewDidLoad];
SpeechRecognizer * speechRecognizer = [[SpeechRecognizer alloc] init];
speechRecognizer.delegate = self;
}
#pragma mark - Delegate Methods
-(void)speechRecognitionFinished:(NSString *) transcription{
//Do something here
}
-(void)speechRecognitionError:(NSError *) error{
//Do something here
}
I had a similar issue after following (import header + Objc annotation on protocol). I got the warning when using Swift code from Objective C headers. Solved by only importing into the implementation .m files.
Add #objc attribute to your protocol:
#objc protocol SpeechRecognizerDelegate : class {
//...
}
Include Swift Classes in Objective-C Headers Using Forward Declarations
//MySwiftClass.swift
#objc protocol MySwiftProtocol {}
#objcMembers class MySwiftClass {}
// MyObjcClass.h
#class MySwiftClass;
#protocol MySwiftProtocol;
#interface MyObjcClass : NSObject
- (MySwiftClass *)returnSwiftClassInstance;
- (id <MySwiftProtocol>)returnInstanceAdoptingSwiftProtocol;
// ...
#end

Use delegate in objective c class to call swift method

I have two files
Question.m
Question.h
These two are written by Objective-C
MainView.swift
This is written by Swift
Question Class has the delegate
#interface Question : NSObject{
id delegate;// put MainViewController here
- (void)trythisfunction{
[delegate test] // compiler doesn't find this method.
}
}
and I make class instance and put MainViewController as delegate of Question in MainViewController.swift
class MainViewController: UIViewController {
override func viewDidLoad(){
q = Question()
q.delegate = self // put self in delegate
}
func test(){
NSLog("test is OK")
}
}
However Compiler found error [delegate test]
Question.m:169:19: No known instance method for selector 'test:'
How can I solve this??
You need to make few changes.
Below class declaration doesn't compile because you can't declare variables inside interface.
#interface Question : NSObject{
id delegate;
- (void)trythisfunction {
[delegate test]
}
}
I have fixed above and the class now looks like this,
# Question.h file
#import <Foundation/Foundation.h>
#interface Question : NSObject
#property (nonatomic, strong) id delegate;
#end
Below is the implementation of the class
# Question.m file
#import "Question.h"
#implementation Question
#synthesize delegate;
- (void)trythisfunction{
[delegate test];
}
#end
As we are integrating this swift and so we will need a Bridging Header whose content look like.
#import "Test.h"
Finally in your swift class now you can import this class
import UIKit
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let q = Test()
q.delegate = self
}
func test(){
NSLog("test is OK")
}
}
And above code works like a charm.