Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call an Objective-C singleton from Swift?

I have an objective-C singleton as follows:

 @interface MyModel : NSObject
    + (MyModel*)   model;
    ...


        + (MyModel*) model 
        {
            static MyModel     *singlton = nil;
            static dispatch_once_t onceToken;
            dispatch_once(&onceToken, ^ {
                singlton = [[MyModel alloc] initSharedInstance];
            });
            return singlton;
        }


        - (MyModel*) initSharedInstance
        {
            self = [super init];
            if (self)
            etc.
        }

Which gets called in multiple places within the GUI code as:

[[MyModel model] someMethod];

And therefore the model will get created as a consequence of whichever part of the GUI happens to reference it first.

I'm not sure how to implement the equivalent of accessing the class via [[MyModel model] someMethod] in Swift as all examples of using Swift involve creating an object using an initializer and when Objective C class method code is converted to Swift initializer code there is a problem with it not working when the method does not have parameters.

like image 443
Gruntcakes Avatar asked Jun 10 '14 18:06

Gruntcakes


People also ask

How do you call a swift singleton class in Objective C?

To use Swift classes in Obj-C you both need to #import "SingletonTest-Swift. h the generated header or forward declaration with @class MySwiftClass . Additionally the class needs to inherit from an Obj-C class like you have don here with NSObject or be marked with @objc to expose it.

How does swift implement Singleton?

In Swift, Singleton is a design pattern that ensures a class can have only one object. Such a class is called singleton class. An initializer allows us to instantiate an object of a class. And, making the initializer of a class restricts the object creation of the class from outside of the class.

Can singleton class be inherited Swift?

A programmer cannot inherit the pure-singleton class. When you try to inherit any class in swift, you must call the constructor of the superclass.

What is singleton class in Objective C?

What is a Singleton Class? A singleton class returns the same instance no matter how many times an application requests it. Unlike a regular class, A singleton object provides a global point of access to the resources of its class.

How do I use swift types in Objective-C?

You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file. This file is an Objective-C header that declares the Swift interfaces in your target, and you can think of it as an umbrella header for your Swift code.

How do you reference a swift header in Objective-C?

When declarations in an Objective-C header file refer to a Swift class or protocol that comes from the same target, importing the generated header creates a cyclical reference. To avoid this, use a forward declaration of the Swift class or protocol to reference it in an Objective-C interface.

How do I call a C library from Swift?

If you want to wrap a C [system] library and call it directly from Swift you can crete a brand new wrapper package with the help of the Swift Package Manager. To start you can use the swift package init --type system-module command, this will create a generic template project.

Does Swift work with C programming language?

This setup also works with C, C++, Objective-C, Objective-C++ code. If you want to wrap a C [system] library and call it directly from Swift you can crete a brand new wrapper package with the help of the Swift Package Manager.


2 Answers

If the Swift compiler mistakenly identifies a method as a class factory method, you can use the NS_SWIFT_NAME macro, passing the Swift signature of the method to have it imported correctly. For example:

+ (id)recordWithQuality:(double)quality NS_SWIFT_NAME(record(quality:));

so,your method should be this:

+ (MyModel*)model NS_SWIFT_NAME(log());
like image 139
eliudnis Avatar answered Nov 10 '22 10:11

eliudnis


UPDATE ++++++++++

The workaround below is only necessary if you name your singleton method with a name derived from the suffix of the class name i.e. the OPs question the method name is model and the class is called MyModel.

If the method is renamed to something like singleton then it is possible to call it from Swift just like this:

  let m  = MyModel.singleton()

+++++++++++

I don't know if this is good/bad practice but I was able to get around the problem with initializer conversion not working when there are no parameters by adding a dummy init method. So using the code from the other answer as an example:

@interface XYZThing : NSObject
+ (XYZThing*)  thing;
+ (XYZThing*)  thingWithFoo:(int)foo bar:(int)bar;
@end

@implementation XYZThing
+ (XYZThing*) thing
{
    NSLog(@"This is not executed");
    return nil;
}

+ (XYZThing*)thingWithFoo:(int)foo bar:(int)bar
{
    NSLog(@"But this is");
    return nil;
}
@end


...

let thing = XYZThing()
let otherThing = XYZThing(foo:3, bar:7)

With this code above the thing method is not called, but the thingWithFoo:bar: method is.

But if it is changed to this then now the thing method will get called:

    @interface XYZThing : NSObject
    + (XYZThing*)  init;
    + (XYZThing*)  thing;
    + (XYZThing*)  thingWithFoo:(int)foo bar:(int)bar;
    @end


    @implementation XYZThing

    + (XYZThing*) init
    {
         return nil;
    }
    + (XYZThing*) thing
    {
        NSLog(@"Now this is executed");
        return nil;
    }

    + (XYZThing*)thingWithFoo:(int)foo bar:(int)bar
    {
        NSLog(@"And so is this");
        return nil;
    }
    @end


...

    let thing = XYZThing()
    let otherThing = XYZThing(foo:3, bar:7)
like image 38
Gruntcakes Avatar answered Nov 10 '22 11:11

Gruntcakes