Swift Singleton Init在XCTest中调用了两次

sta*_*guy 8 singleton objective-c ios swift

随着斯威夫特,一个单初始化被称为两次运行XCTest单元测试时.

但是,没有Objective-C的问题,init()方法只按预期调用一次.

以下是构建两个测试项目的方法:

Objective-C的

单身人士班

使用测试创建一个空的Objective-C项目.添加以下裸机单例:

#import "Singleton.h"

@implementation Singleton

+ (Singleton *)sharedInstance
{
    static Singleton *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[Singleton alloc] init];
        // Do any other initialisation stuff here
    });
    return sharedInstance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSLog(@"%@", self);
    }
    return self;
}
@end
Run Code Online (Sandbox Code Playgroud)

AppDelegate中

在应用程序委托中添加对单例的调用,如下所示:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    [Singleton sharedInstance];
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

XCTestCase

还要对生成的测试类添加对单例的调用:

- (void)testExample {
    [Singleton sharedInstance];
    // This is an example of a functional test case.
    XCTAssert(YES, @"Pass");
}
Run Code Online (Sandbox Code Playgroud)

结果

如果向单例的init方法添加断点并运行测试,断点将仅按预期命中一次.

迅速

现在创建一个新的Swift项目并做同样的事情.

独生子

创建单例,将测试目标添加到其中 Target Memberships

class Singleton {
    class var sharedInstance : Singleton {
        struct Static {
            static var onceToken : dispatch_once_t = 0
            static var instance : Singleton? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = Singleton()
        }
        return Static.instance!
    }

    init() {
        NSLog("\(self)")
    }
}
Run Code Online (Sandbox Code Playgroud)

AppDelegate中

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // Override point for customization after application launch.
    Singleton.sharedInstance
    return true
}
Run Code Online (Sandbox Code Playgroud)

XCTestCase

func testExample() {
    // This is an example of a functional test case.
    Singleton.sharedInstance
    XCTAssert(true, "Pass")
}
Run Code Online (Sandbox Code Playgroud)

结果

这一次,如果你向单例的init方法添加一个断点并运行测试,断点将被击中两次,首先来自app委托,然后来自测试用例,即你将有两个单例实例.

我错过了什么吗?

rin*_*aro 9

由于应用模块和测试模块分离的模块,当你添加的Singleton.swift文件来测试目标会员,YourApp.SingletonYourAppTest.Singleton不是同一类.这就是为什么init叫两次.

而不是那样,您应该import在测试文件中使用主模块:

import YourAppName

func testExample() {
    // This is an example of a functional test case.
    Singleton.sharedInstance
    XCTAssert(true, "Pass")
}
Run Code Online (Sandbox Code Playgroud)

并且您的Singleton类必须声明为public.请参阅Swift,访问修饰符和单元测试

public class Singleton {
    public class var sharedInstance : Singleton {
        struct Static {
            static var onceToken : dispatch_once_t = 0
            static var instance : Singleton? = nil
        }
        dispatch_once(&Static.onceToken) {
            Static.instance = Singleton()
        }
        return Static.instance!
    }

    init() {
        NSLog("\(self)")
    }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记Singleton.swift从测试目标成员身份中删除.

  • 哇,希望我 2 小时前就看到了这个 (2认同)