首页 文章

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

提问于
浏览
9

我有一个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 回答

  • 10

    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)
    
  • 6

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

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

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

    + (MyModel*)model NS_SWIFT_NAME(log());
    
  • 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

相关问题