【问题标题】:Swift Singleton Init Called Twice in XCTestSwift Singleton Init 在 XCTest 中调用了两次
【发布时间】:2014-11-27 14:02:46
【问题描述】:

在 Swift 中,单例初始化程序在运行 XCTest 单元测试时被两次调用。

Objective-C 没有问题,但 init() 方法只被调用一次,正如预期的那样。

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

目标-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

AppDelegate

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

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

XCTestCase

同时添加对生成的测试类的单例调用:

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

结果

如果您在单例的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)")
    }
}

AppDelegate

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

XCTestCase

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

结果

这一次,如果你在单例的init 方法中添加一个断点并运行测试,断点将被命中两次,首先来自应用委托,然后来自测试用例,即您将拥有两个单例实例。

我错过了什么吗?

【问题讨论】:

标签: ios objective-c swift singleton


【解决方案1】:

由于应用模块和测试模块是分开的模块,当你将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")
}

并且您的Singleton 类必须声明为public。见Swift, access modifiers and unit testing

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)")
    }
}

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

【讨论】:

  • 哇希望我在 2 小时前看到这个
  • 是的!我的问题是我将我的单例添加到两个目标中,因此它能够创建单独的单例实例......谢谢!
  • 我已正确完成以下所有设置,但问题仍然存在。奇怪的是我的项目构建得很好,但是只有当我尝试在项目的第一个 SwiftUI 文件上渲染视图时才会发生失败。很奇怪。构建失败是因为我在测试中导入了我的 appname,构建错误参考了这篇文章。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-20
  • 2014-09-22
  • 2013-05-29
  • 2012-12-26
  • 2020-06-18
相关资源
最近更新 更多