iOS - Can't access Swift Singleton from Objective-C - ios

I can't access my Swift Singleton Class from my Objective-C ViewController.
Xcode does recognize my Swift Class, it builds, so I don't think it is a bridging header issue.
Here is my Swift Singleton Class :
#objc class MySingleton : NSObject {
static let shared = MySingleton()
private override init() {}
}
And then in my .m file I import this header :
#import "myProject-Swift.h"
And use the Singleton this way :
MySingleton *testSingleton = [MySingleton shared];
or this way :
[MySingleton shared];
It does recognize the MySingleton class type, but I can't access any functions or properties of this class.
What am I missing? All the similar posts didn't help.
EDIT: I made a test function
func testPrint() {
print("Singleton worked")
}
And called it this way in the objective-c file :
[[MySingleton shared] testPrint];
No known instance for selector 'testPrint'

In your Swift Singleton class, add #objc for the method testPrint() like:
#objc func testPrint() {
print("Singleton worked")
}
Now, you access the method from Objective-C class:
[[MySingleton shared] testPrint];

use #objc attribute before the testPrint() function. refer 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.

You need to add #objc to any property or function you want to expose to Objective-C, including the static shared property:
class MySingleton : NSObject {
#objc static let shared = MySingleton()
private override init() { }
#objc func testPrint() { print("Singleton worked") }
}
Then, the call from Objective-C file:
MySingleton *singleton = [MySingleton shared];
[singleton testPrint];
Note that marking the whole class as #objc isn't a replacement for the above. It is actually not needed anymore, and it's enough to inherit from NSObject.

Related

Accessing Swift Protocol in Objective C and then back on Swift

I'm a new comer into Objective-C and swift and I need to make changes to an existing code base.
I have added a protocol defined in Swift
File AController.swift
#objc
protocol MyDelegate: NSObjectProtocol {
func saveTapped()
func discardTapped()
}
#objc
class AController: UIViewController, BcAiDelegate {
...
}
The protocol is used as a member is BController.h
and the code compiles and builds w/o issues
// imports are placed here
// #class declarations are here
#protocol MyDelegate;
...
#property (nonatomic) MyDelegate* myDelegate;
#property (nonatomic) BOOL myFlag;
And then I try to access this field in CController.swift
#objcMembers class CController: UIViewController {
...
func doSomething() {
let bController = BController()
// When I try to access `myDelegate` it isn't recognized as a member of the controller
// I get an error message that says - Value of type 'BController' has no member 'myDelegate'
bController.myDelegate = nil
bController.myFlag = true // This lines works fine
}
...
}
If I look at the swift 5 interface generated from BController.h I can see the following definitions:
...
open var myDelegate: UnsafeMutablePointer<Int32>!
open var myFlag: Int33
...
I tried created new initializers in BController.h, one that receives a Bool and the other that receives MyDelegate - and the behavior is the same, the one with Bool is accessible in CController.swift and the other isn't
Obviously I'm missing some part - but what?

Is it possible to call objective C application delegate method from Swift class of the same project?

I'm merging my Swift project with already existing Objective-C code. I need to call some important methods of Swift class from objective C app delegate. I tried all methods given in net, but it was no use. Can any one help me out?
Yes, it's possible but with some limitations.
You can use only classes which inherited from NSObject, with public attribute and marked with #objc. At Objective-C code you should import "ProductModuleName-Swift.h" file which generated by compiler.
Here is an example of Swift class:
import Foundation
#objc public class ExampleClass: NSObject {
#objc public var someInstanceProperty = "Property"
#objc public func someFunction() {
print("Some function")
}
}
Notice that this class inherited from NSObject and have #objc and public attributes. After command+B you can take a look at generated bridge header through Assistance editor:
Then you should import the bridge header at your Objective-C class.
#import "ProductModuleName-Swift.h"
And then you can use your Swift class at Objective-C code like any other Objective-C class:
__auto_type const someClass = [ExampleClass new];
[someClass someFunction];
NSLog(#"%#", someClass.someInstanceProperty);
Here is an additional information from Apple:
Importing Swift into Objective-C

Exposing Swift internal func to Objective-C file(in framework) without making it public

I have a Swift framework in which I have an Objective-C file. From that file I want to access a method which is declared as internal. I know that I can change it to public to make it available. But I don't want to expose it to the client app. Is there any way to achieve this?
In .swift:
#objc internal class func callBack(str: String) {
print("Swift method was called | Passed value: " + str)
}
In .m:
- (void)callSwiftFunc {
// This is not available, only if I set public in Swift
[SwiftClass callBackWithStr:#"blabla"];
}
You can explicitly set the objc selector and then add a category which declares the method:
replace #objc with #objc(callBackWithStr:), then simply add a forward declaration:
#interface SwiftClass ()
+ (void)callBackWithStr:(NSString *)string;
#end

How to use Notification.Name extension from Swift to Objective-C?

I created an extension for Notification.Name as below:
public extension Notification.Name {
public static let blahblahblah = Notification.Name(rawValue: "blahblahblah")
}
Now I want to use this extension in Objective-C, but it's not accessible even if its public.
How can I access and use this Swift extension in both Objective-C and Swift?
Previously I was using constant values in Objective-C, but now I'm upgrading my code and want to use this extension.
My extension in swift file
extension Notification.Name {
static let purchaseDidFinish = Notification.Name("purchaseDidFinish")
}
#objc extension NSNotification {
public static let purchaseDidFinish = Notification.Name.purchaseDidFinish
}
// OBJECTIVE-C
#import YourProjectName-Swift.h
[NSNotificationCenter.defaultCenter addObserver:self selector:#selector(purchaseDidFinish) name:NSNotification.purchaseDidFinish object:nil];
// SWIFT
NotificationCenter.default.addObserver(self, selector: #selector(purchaseDidFinish), name: .purchaseDidFinish, object: nil)
#objc func purchaseDidFinish(notification: Notification) {
print("purchaseDidFinish")
}
#leanne's answer was super helpful
Notification.Name doesn't exist in Objective-C. And the Objective-C type NotificationName is really just an NSString. To use Swift stuff in Objective-C, the class must be available in both, and can't be a Swift struct (like Notification or String, say).
To do what you want, then, you need to have two extensions:
one for the Swift Notification.Name, as you have; and,
one for an Objective-C object (NSString, say, or perhaps NSNotification if you prefer).
1) Add an Objective-C-compatible object extension to your Swift file:
public extension NSNotification {
public static let blahblahblah: NSString = "blahblahblah"
}
Note: in Swift 4, properties must be computed for Objective-C compatibility. That would look like:
#objc public extension NSNotification {
public static var blahblahblah: NSString {
return "blahblahblah"
}
}
Note the var in the computed property: computed properties can't be immutable, so can't use let.
2) In the Objective-C file, import Xcode's generated Swift header file (below any other imports):
#import "YourProjectName-Swift.h"
Note: replace YourProjectName with the actual name of your project. So, if your project is named "CoolGameApp", the Swift header would be "CoolGameApp-Swift.h". If your project name has spaces, like "Cool Game App", replace them with dashes: "Cool-Game-App-Swift.h"
3) Rebuild the project.
Now, you should be able to access the extension in Objective-C:
[[NSNotificationCenter defaultCenter] postNotificationName:NSNotification.blahblahblah object:self];
In addition to the answers here, I had to add #objc to my NSNotification extension before my Obj-C code could see it (Swift 4).

How to conform swift class delegate in objective c Class using swift 4?

Suppose there are two class one in swift and other is in objective-c class in same project.
In swift class i declared delegate and i want to set that delegate in objective c class.
I have done this following way ...
import UIKit
#objc public protocol SwiftLoginVCDelegate: class {
}
#objc public class SwiftLoginViewController: UIViewController {
#IBOutlet var txtUserName: UITextField!
#IBOutlet var txtPassword: UITextField!
#IBOutlet var btnLogin: UIButton!
var delegate: SwiftLoginVCDelegate?
override public func viewDidLoad() {
super.viewDidLoad()
self.txtPassword.text = "XYZ"
self.txtPassword.text = "123"
self.btnLogin.backgroundColor = UIColor.blue
}
#objc public func testObjective(){
print("Swift class is integrated in objective c project")
}
the objective c class is
#import "Mediator.h"
#class SwiftLoginViewController;
#protocol SwiftLoginVCDelegate;
#interface LoginMediator : Mediator
#end
Implementation Class is
#import "xyz-Swift.h"
#class SwiftLoginViewController;
#implementation LoginMediator
-(void)onRegister
{
// line 1: [(XYZController*)self.viewComponent setDelegate:self];
line 2 : [(SwiftLoginViewController*)self.viewComponent setDelegate:self];
[objectVC testObjective];
}
If u check the onRegister Method , In line No 1 delegate is set using objective c, which is commented now , but i want to set same delegate in swift 4 , line no 2, when I try to set delegate in swift 4 I am getting following error
No visible #interface for 'SwiftLoginViewController' declares the
selector 'setdelegate';
Note :
One more that i am able to access all the var and function defined in
swift class to objective c Class. I am not able to set the
Delegate in objective c Class which is declared in swift Class.
Can any one has any idea what i am doing wrong in above code ? All inputs are appreciated.
Okay so I've made a sample project in Objective-C and then installed my Swift framework called GPKit, once I made it working, I realized you're not using Cocoapod. So I made a sample Swift class and then used it in my Objective-C class.
First, you need to learn how to properly use a Swift file/class inside your Objective-C class, learn from here: Can't use Swift classes inside Objective-C
And then once you get it working, confirming to a Swift delegate and implementing the functions in that delegate will be easy.
What I can see in your implementation is that you're making a new class and protocol.
#class SwiftLoginViewController;
#protocol SwiftLoginVCDelegate;
Here's the sample code that I made just for this question:
ViewController.m
#import "TestObjcUsingGPKit-Swift.h"
#import "ViewController.h"
#interface ViewController () <CuteDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CuteClass *newCutie = [[CuteClass alloc] init];
newCutie.delegate = self;
}
- (void)myCuteFunc {
// --- the delegate function
}
#end
CuteClass.swift
import UIKit
#objc public protocol CuteDelegate: NSObjectProtocol {
#objc func myCuteFunc()
}
public class CuteClass: NSObject {
weak var delegate: CuteDelegate?
}
The full sample project on GitHub for you: https://github.com/glennposadas/UsingSwift-In-ObjectiveC
I had the exact same issue as you. I noticed that the generated -Swift.h file did not expose the weak delegate member in my Swift file to the objective-c runtime. You can verify this by doing a command+click on your #import -Swift.h file and search for you Swift class name to see what methods/members are exposed.
To finally fix the issue, I ended up adding the #objc tag to my delegate. In your case it would be:
#objc weak var delegate: SwiftLoginVCDelegate?
After I did that, I observed the -Swift.h file again, and lo and behold my delegate was exposed and I'm able to use it in my objective c file as expected.
Hope this helps.
#Gleen response is fine but you must add #objc to var delegate too
weak var delegate: CuteDelegate?
The issue is coming from using setdelegate instead of setDelegate ( see the lowercase delegate).
Try:
[(SwiftLoginViewController*)self.viewComponent setDelegate:self];
// or
((SwiftLoginViewController*)self.viewComponent).delegate = self;
I was stuck on this until I found a different problem: I had #objcMembers on the Swift class definition, but the protocol definition sits outside of the class definition and needs its own #objc annotation.

Resources