Can not find Swift Protocol declaration in Obj-C class - objective-c

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

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 protocol called in Objective-C not working and application crashes with error message "unrecognized selector"

I am trying to get the Swift protocol to work in Objective-C file, but the application crashes when the error as below.
+[OpenCamera onCameraClose]: unrecognized selector sent to class 0x102ff8580
I am not sure as to what I am missing.
//Swift: UIViewController Code
#objc protocol CameraViewControllerDelegate {
func onCameraClose()
}
#objc class CameraViewController: UIViewController {
var delegate : CameraViewControllerDelegate? = nil
func closeCamera(sender: Any) {
delegate?.onCameraClose()
}
}
// Objective-C : UIViewController Code
OpenCamera.h
#interface OpenCamera : UIViewController <CameraViewControllerDelegate>
OpenCamera.m
#import <MyProjectName/MyProjectName-Swift.h>
#implementation OpenCamera
- (void)viewDidLoad {
[super viewDidLoad];
CameraViewController *cameraViewController = [[CameraViewController alloc] initWithNibName:#"CameraView" bundle:nil];
cameraViewController.delegate = self; //Warning - Incompatible pointer types assigning to 'id<CameraViewControllerDelegate> _Nullable' from 'Class'
}
- (void)onCameraClose {
NSLog(#"Swift Protocol method executed from Objective-C");
}
#end
The warning here did in fact predict the crash:
cameraViewController.delegate = self;
//Warning - Incompatible pointer types assigning to 'id<CameraViewControllerDelegate> _Nullable' from 'Class'
Clearly it thinks self is a class, not an instance. That's very odd.
My guess is that there is something wrong with your import arrangements, but you have not shown enough information to see what it is. I'll just show an arrangement that works.
Let's assume you have both Objective-C and Swift code in one target (i.e. that no frameworks are involved). Then in Swift, you say:
#objc protocol CameraViewControllerDelegate {
func onCameraClose()
}
class CameraViewController: UIViewController {
#objc var delegate : CameraViewControllerDelegate? = nil
func closeCamera(sender: Any) {
delegate?.onCameraClose()
}
}
Note the use of #objc var to expose the delegate property. There is no need to expose the class to Objective-C, as it is already an NSObject derivative.
Okay, in Objective-C, here is your interface file:
#import <UIKit/UIKit.h>
#interface OpenCamera : UIViewController
#end
Note that you do not import the generated header in a .h file, and you do not attempt to mention an imported protocol here.
On to the implementation file:
#import "OpenCamera.h"
#import "MyProject-Swift.h"
#interface OpenCamera () <CameraViewControllerDelegate>
#end
#implementation OpenCamera
- (void)viewDidLoad {
[super viewDidLoad];
CameraViewController *cameraViewController = [[CameraViewController alloc] initWithNibName:#"CameraView" bundle:nil];
cameraViewController.delegate = self;
}
- (void)onCameraClose {
NSLog(#"Swift Protocol method executed from Objective-C");
}
#end
We import the corresponding .h file and the generated header .h file here. We use an anonymous category to declare conformance to the protocol, and the rest is as you have it. You won't see any warnings.

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.

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.

Using a Swift protocol in Objective-C

I'm working on converting my project from Objective-c to Swift, and a Swift class I'm using, I have a protocol I'm trying to access in an Objective-c class. My problem is, the delegate is not accessible in the objective-c class. Here is my swift class:
protocol RateButtonDelegate {
func rateButtonPressed(rating: Int)
}
class RateButtonView: UIView {
var delegate: RateButtonDelegate?
var divider1: UIView!
var divider2: UIView!
}
When I look at the MyProject-Swift.h file, I don't see the delegate:
#interface RateButtonViewTest : UIView
#property (nonatomic) UIView * divider1;
#property (nonatomic) UIView * divider2;
#end
and when I try to use rateButtonView.delegate in my Objective-c class, I get a compiler error.
Anyone know the issue? How do access a Swift protocol in Objective-c?
You need to mark your protocol with the #objc attribute for it to be accessible from Objective-C:
#objc protocol RateButtonDelegate {
func rateButtonPressed(rating: Int)
}
This page from Apple's documentation covers the issue.