如何从Swift调用Objective-C单例?

时间:2014-06-10 18:35:09

标签: objective-c swift

我有一个Objective-C单身如下:

 @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.
        }

在GUI代码中的多个位置调用它:

[[MyModel model] someMethod];

因此,模型将被创建,因为GUI的任何部分都会首先引用它。

我不确定如何通过Swift中的[[MyModel model] someMethod]实现相应的访问类,因为使用Swift的所有示例都涉及使用初始化程序创建对象以及将Objective C类方法代码转换为当方法没有参数时,Swift初始化代码存在问题,它无法正常工作。

3 个答案:

答案 0 :(得分:11)

UPDATE ++++++++++

只有在使用从类名后缀派生的名称命名单例方法时,才需要使用下面的解决方法,即OPs问题方法名称是模型,类名为MyModel。

如果将方法重命名为singleton,则可以从Swift中调用它:

  let m  = MyModel.singleton()

+++++++++++

我不知道这是好/坏的做法,但是当通过添加虚拟init方法没有参数时,我能够解决初始化程序转换无法正常工作的问题。因此,使用其他答案中的代码作为示例:

@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)

上面的代码没有调用thing方法,但是thingWithFoo:bar:方法是。

但是如果它改为this,那么现在将调用thing方法:

    @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)

答案 1 :(得分:6)

如果Swift编译器错误地将方法识别为类工厂方法,则可以使用NS_SWIFT_NAME宏,传递方法的Swift签名以正确导入它。例如:

+ (MyModel*)model NS_SWIFT_NAME(log());

所以,你的方法应该是这样的:

This is a crawling bug that we've now implemented handling for.
We are running a script that will check for queued scheduled crawls every hour
and start them if they are not running.

答案 2 :(得分:3)

完全按照编译器警告的要求进行操作:

MyModel().someMethod()

请继续阅读以了解原因......


Swift自动识别初始化器和便捷构造器的ObjC约定。如果你有一个类似这样的类:

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

...然后,当Swift将它们转换为初始值设定项时,它忽略了方法名称的一部分,即该类的通用名称(Thing / thing),移动选择器的一部分,它将参数引用为参数标签,并删除连接这些部分的所有介词。所以初始化器声明在Swift中看起来像这样:

class XYZThing: NSObject [
    init()
    init(foo: Int, bar: Int)
}

你构建这样的对象:

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

后续:因为像+[XYZThing thing]这样的类方法被ObjC to Swift翻译器处理为初始化器(即使它现在似乎没有完全起作用),这种命名模式对于单身。单例检索方法不应该是初始化器,因为初始化器总是创建一个新实例。

单例检索方法应该具有一个不以该类的通用名开头的名称;例如+sharedThing+defaultThing+oneThingToRuleThemAll