Amino acids Amino acids - 6 months ago 17
Objective-C Question

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.

Answer

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)