I'm fairly new to objective-c and swift so forgive me if this sounds dumb. Basically what I'm trying to do is *expose** a swift function to both react-native(so it can be used in JS) and to be used in objective-c. The issue I'm having is this dreaded "Duplicate interface definition for class...". I have researched and tried everything it seems but can not get rid of this error. I'm starting to wonder if is possible to do this. It seems so simple yet I just can't figure it out!
Here is my code:
AppDelegate.m
#import "MyApp-Swift.h"
#import "MyApp-Bridging-Header.h"
MyApp-Swift.h
#import "React/RCTEventEmitter.h"
#interface Counter : RCTEventEmitter
- (void)start;
- (void)stop;
#end
MyApp.swift
import Foundation
import UIKit
#objc(Counter)
class Counter: RCTEventEmitter {
#objc func start(){
}
#objc func end(){
}
}
MyApp-Bridging-Header.h
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
#import "React/RCTEventEmitter.h"
#interface RCT_EXTERN_MODULE(Counter, RCTEventEmitter)
RCT_EXTERN_METHOD(start);
RCT_EXTERN_METHOD(end);
#end
Inside AppDelegate.m didFinishLaunchingWithOptions() function
Counter* CounterInstance = [[Counter alloc] init];
[CounterInstance start];
If I remove the code from MyApp-Swift.h then I get the error "No visible #interface for..." BUT fixes the "Duplicate interface error" in MyApp-Bridging-Header.h. It seems like it contradicts each other!? How are you supposed to call a swift function from objective-c while also exposing the same function to JS?
I'm doing something similar in a project, and my setup looks like this:
Counter.m
#import "React/RCTBridgeModule.h"
#import "React/RCTViewManager.h"
#interface RCT_EXTERN_MODULE(Counter, NSObject)
RCT_EXTERN_METHOD(start)
RCT_EXTERN_METHOD(stop)
#end
Counter.swift
import React
#objc(Counter)
class Counter: RCTEventEmitter {
#objc func start() { /* ... */ }
#objc func stop() { /* ... */ }
}
and at the call site:
#import "YOURAPP-Swift.h" // the compiler creates this for you. don't edit!
-(void) foo {
Counter* cnt = [Counter new];
[cnt start];
}
(no other files used or modified. In particular, the bridging header isn't needed here)
I've found https://teabreak.e-spres-oh.com/swift-in-react-native-the-ultimate-guide-part-1-modules-9bb8d054db03 very helpful when I started doing this.
Related
I have framework that written in Swift like this.
import Foundation
import WebKit
import ObjectiveC
public extension WKWebView {
public func someFunc(_ completionHandler:#escaping (_ capturedImage: UIImage?) -> Void) {
//Some code
}
}
When I build the frameworks and import to Objective-C code that use Cocoapods for Dependency Manager. I Can't call above someFunc function. The error said this:
No visible #interface for 'WKWebView' declares the selector 'someFunc'
This is how I implement Swift framework in Objective-C:
#import <Foundation/Foundation.h>
#import <ProjectName-umbrella.h>
#implementation CapturerDefault
- (void)captureWebViewScreenWith:(UIView *)containerView
andCompletionHandler:(void (^)(UIImage *))completion {
WKWebView *webView = [self findWebViewInViewController:containerView];
[webView someFunc: resultImage] //The error show here.
}
}
What is wrong? Did i miss something?
I tried the following steps and it works for me:
Don't import the swift file in your objc file like: #import "ExampleFile.swift" but use #import "ProjectName-Swift.h"
Make sure you use #objc statements in your swift code that you want to import to objc
Swift file:
import WebKit
extension WKWebView {
#objc public func someFunc() {
}
}
Objective C file:
#import "ViewController.h"
#import "Sample-Swift.h"
#import <WebKit/WebKit.h>
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
WKWebView *wbView = [[WKWebView alloc]init];
[wbView someFunc];
}
Credits to:
"Expected ';' after top level declarator" under Swift
I'm doing a Tweak and i use Flex to edit some Obj-C but one of these i cant edit so, i think if i do a Tweak with MSHook can resolve this, BUT NO idk how to write correctly i'm new on this, i want to disable "shootCooldown" but idk if is posible, so this is my code on Tweak.x
#import <substrate.h>
#import <Foundation/Foundation.h>
#interface ControlsWidget : NSObject {
NSString *_shootCooldown;
}
#end
NSString *_shootCooldown;
%hook ControlsWiget
{
shootCooldown = MSHookIvar<BOOL>(self, "_someBOOL");
}
%end
I'm successfully mixing and matching Obj-C and Swift in an Xcode 7 project. However, I can't seem to figure out how, in an Objective C class, to inherit from a Swift class (and yes I know about declaring that Swift class as #objc for visibility). In this case the desired Swift superclass MySwiftViewController is a subclass of UIViewController. For now, in Obj-C, I'm inheriting directly from UIViewController and not gaining access to the capabilities I added in MySwiftViewController.
Here's what i understand:
-- To declare an Obj-C class as inheriting from something, that must be in the .h file after the ':':
#import <UIKit/UIKit.h>
#interface RootViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
-- To make Swift classes visible, that is #imported:
#import "MyProject-Swift.h"
However, you cannot import the Swift auto-generated bridging header into the Obj-C .h file. You also cannot forward-declare an opaque superclass with #class. So, is this possible and how?
Unfortunately, it's not possible to subclass a Swift class in Objective-C. Straight from the docs:
You cannot subclass a Swift class in Objective-C.
See Apple's guide on interoperability for more details on what you can and cannot access with Objective-C.
As for Xcode 8.0 and earlier there is dirty-hacky solution, that probably will be fixed in the future.
If you want to subclass from swift file, you can add objc_subclassing_restricted attribute. You can make it as macro for convenience.
Code:
Swift class.
import Foundation
class SwiftClass : NSObject {
func say() {
print("hi");
}
}
Objc class:
#import <Foundation/Foundation.h>
#import "test-Swift.h"
#define SWIFT_SUBCLASS __attribute__((objc_subclassing_restricted))
SWIFT_SUBCLASS
#interface ObjcClass : SwiftClass
- (instancetype)init;
#end
#implementation ObjcClass
- (void)say {
NSLog(#"oops");
}
#end
But, as I understand, it is not supported, and you may have any sort of bugs because of it. So it is not guide to action, and more like curious thing to know.
In fact, it can be achieved by category:
Swift code
import UIKit
#objc open class TestModel: NSObject {
#objc var testName: String = String()
}
Objective C .h file code
#import <Foundation/Foundation.h>
#import "Test-Swift.h"
#interface TestModel (Add)
- (void)configTestName;
#end
Objective C .m file code
#import "TestModel+Add.h"
#implementation TestModel (Add)
- (void)configTestName {
self.testName = #"12323";
}
#end
I'm writing some Swift classes that build upon functionality in our objective-c app. I have a objective-c class with a delegate that conforms to a protocol. I'm trying to call a method on that delegate from inside of a Swift class I'm simplified it down to this.
FredTestProtocol.h:
#protocol FredTestProtocol
- (void) dumbMethod;
#end
FredTestClass.h:
#import <Foundation/Foundation.h>
#import "FredTestProtocol.h"
#interface FredTestClass : NSObject <FredTestProtocol>
#property (nonatomic, weak) NSObject <FredTestProtocol> *delegate;
#end
FredTestClass.m:
#import "FredTestClass.h"
#implementation FredTestClass
- (void) dumbMethod
{
NSLog(#"Boy, this is a dumb method");
}
#end
FredSwiftClass.swift
import Foundation
class FredSwiftClass {
func test()
{
let ocObject = FredTestClass()
ocObject.delegate.dumbMethod() // Error occurs here.
}
}
The indicated line produces the error "'NSObject' does not have a method named 'dumbMethod'" I've tried a lot of ways to eliminate the error, to no avail. I'm sure I'm missing something really fundamental. Can someone tell me how I should go about calling the delegate method from Swift?
When Swift examines the property delegate it simply sees that is is an NSObject and the fact that you have noted that it implements a protocol is ignored. I can't find any specific documentation as to why this is the case.
You can address this in a couple of ways.
First, you can redefine your delegate property to use class anonymity, then Swift will just see it as some object that implements the protocol -
FredTestClass.h
#import <Foundation/Foundation.h>
#import "FredTestProtocol.h"
#interface FredTestClass : NSObject <FredTestProtocol>
#property id<FredTestProtocol> delegate;
#end
Then your Swift code will compile as written.
or you can leave your delegate definition as is and tell Swift that you want to access the delegate as an instance of an object that implements the protocol via downcast -
FredTestSwift.swift
import Foundation
class FredSwiftClass {
func test()
{
let ocObject = FredTestClass()
let theDelegate=ocObject.delegate as! FredTestProtocol
theDelegate.dumbMethod()
}
}
Pretty sure I've got it.
func test()
{
let ocObject = FredTestClass()
if let myDelegate = ocObject.delegate as? FredTestProtocol
{
myDelegate.dumbMethod()
}
}
I am new to objective C and trying to implement objection (dependency injector).
But its not working below is the code i am using
My Protocol File
#import <Foundation/Foundation.h>
#protocol InfoquestProtocolTest <NSObject>
-(void):nothing;
#end
My .h file is below
#import <Foundation/Foundation.h>
# import "InfoquestProtocolTest.h"
#interface InfoquestImplementation : NSObject<InfoquestProtocolTest>
#end
my .m file implementing protocol
#import "InfoquestImplementation.h"
#implementation InfoquestImplementation
-(void):nothing{}
#end
Code for module file of objection
#import "InfoquestTestConf.h"
#import <Objection/Objection.h>
#import "InfoquestViewController.h"
#import "InfoquestImplementation.h"
#implementation InfoquestTestConf
-(void)configure
{
[self bindClass:[InfoquestImplementation class] toProtocol:#protocol(InfoquestProtocolTest)];
}
#end
Code for getting object from objection
JSObjectionInjector *injector = [JSObjection createInjector];
[JSObjection setDefaultInjector:injector];
InfoquestTestConf *Module = [[InfoquestTestConf alloc] init];
[injector withModule: Module];
id<InfoquestProtocolTest> testing2 = [injector getObject:[#protocol(InfoquestProtocolTest)];
But when i try to call using [testing2 nothing]; i am getting error and autocomplete doesnt show up nothing.
Thanks
gaurav
You have a syntax error:
You should replace:
-(void):nothing;
with
-(void)nothing;
here is an error in your syntax.please change :
-(void):nothing;
to:
-(void)nothing;
Hence you are using custom delegates. So first you have to set the delegate to your class where you are implementing the method of your protocol.