【问题标题】:iOS Testing: dispatch_once get called twice. First in App, second in Test. Problems with ObserversiOS 测试:dispatch_once 被调用两次。应用第一,测试第二。观察者的问题
【发布时间】:2014-01-27 16:28:27
【问题描述】:

我有一个将在应用委托中创建的单点类。

当我运行 XCTTests 时,它会再次创建。

+ (instancetype)urlSchemeManager
{
    static dispatch_once_t onceToken;
    static UrlSchemeManager* _sharedInstance;

    dispatch_once(&onceToken, ^{

        _sharedInstance = [UrlSchemeManager new];


    });
    return _sharedInstance;
}

这会导致两个不同的实例。如果我只是将它用于单元测试,这没问题。 但是在集成测试中,当我为 urlSchmemeManager 注册一个观察者时,我得到一个 EXC_BAD_ACCESS,因为它已经被 rootViewController(在 UI 中)观察到了。

在 RootViewController 中:

UrlSchemeManager * schemeManager = [GlobalSpace globalSpace].urlSchemeManager;
[schemeManager addObserver:self forKeyPath:OBSERVER_KEY_URL_SCHEME_MANAGER_CONTENT_MORE options:NSKeyValueObservingOptionNew context:nil];

有人知道我该如何解决这个问题吗?

【问题讨论】:

  • when i register an observer vor urlSchmemeManager i get a EXT_BAD_ACCESS vor 代表什么?
  • 我更新了源代码来解决这个问题。
  • 您不是说 EXC_BAD_ACCESS 吗?您能否提供有关此异常的更多信息(例如堆栈跟踪)
  • _sharedInstance 只能有两个不同的实例 IFF 有两个onceToken 的不同实例。例如,当您有两个包,每个包都包含定义 onceToken 的模块并且这些包将通过动态链接器链接到一个应用程序时,可能会发生这种情况。
  • 这听起来很可能是原因。你知道如何解决这个问题吗?

标签: ios testing grand-central-dispatch observers xctest


【解决方案1】:

在运行测试套件时多次调用 dispatch_once 时,我遇到了同样的问题。我通过从测试的目标成员中删除单例类来修复它。

完成后,请确保您的测试目标在“构建阶段”中依赖于您的应用程序,以便测试仍然了解该类。

之后,测试应该运行并且单例应该只被实例化一次。

【讨论】:

  • 这是正确的解决方案,我几乎失去了对计算机的信念,即 dispatch_once 被执行两次......谢谢!
  • 太棒了!你拯救了我的一天。
  • 如果单例文件未包含在测试目标中并给出“使用未解析的标识符”错误,则测试不会编译。
【解决方案2】:

迈克的回答是正确的!只是添加更多信息。这是一个非常棘手的问题。似乎是 app 目标和测试目标是分开编译的。然而,在运行时,测试的二进制文件被注入到应用程序的空间中。因为检测重复符号通常是编译器的工作,并且编译过程不同,所以在运行时可能会出现一个类的两个实例。类的每个实例都有自己的一组静态变量。这太奇怪了。大量奇怪的行为可能源于此。包括两次 dispatch_once_t 执行。

我在 cocoapods 课程中遇到了这个问题。默认情况下,Podfile 中的所有 pod 都链接到所有目标。因此,在运行 XCTest 时,您将在运行时出现重复的类。解决方案是为每个目标指定您的 pod。以我为例。我做到了:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '7.0'

target 'MyApp', :exclusive => true do
    pod 'AFNetworking'
    pod 'ObjectiveRecord', :head
    ...
end

target 'MyApp Tests', :exclusive => true do
  pod 'KIF', '~> 3.0', :configurations => ['Debug']
end

inhibit_all_warnings!

ObjectiveRecord 中的单例模式特别有问题。因为核心数据上下文管理器类被创建了两次,所以我的应用程序的不同部分没有看到相同的数据。

【讨论】:

  • 谢谢,这正是我的问题 :)(顺便说一句,我认为您也不需要这两个 :exclusive => trues。)
  • 这是一个绝妙的答案!
  • 我通过从测试目标编译中排除我的单例解决了我的问题。问题是它被标记为 app 和 unitTest 目标的编译。这就是重复符号的来源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多