【问题标题】:Weird singleton initialization in static function initialize during unit tests静态函数中奇怪的单例初始化在单元测试期间初始化
【发布时间】:2011-02-22 19:19:00
【问题描述】:

我的单例类中有以下代码

static MySingleton *gManager;
+(void)initialize
{
   if(self == [MySingleton class])
   {
       gManager = [[MySingleton alloc] initWithServices:[[MyServices alloc] init]];
   }
}
+(MySingleton *)sharedInstance
{
   return (gManager);
}

不幸的是,在单元测试期间,我看到 gManager 是 SenTestCaseRun 类型的实例。我似乎无法弄清楚为什么? 所以像这样的电话 [[MySingleton sharedInstance] myFunction];

导致 myFunction 是未知选择器的错误,尽管它存在于 MySingleton 类中。

它是 SenTestCaseRun 类型,因为我使用 NSStringFromClass 函数进行了检查。

有什么建议吗?已经为此敲了 3-4 个小时的头:(。

【问题讨论】:

  • 我不知道这是什么语言,但实际上看起来不像C
  • 我认为 OP 在标签框中输入了objective c。修好了。
  • 它是客观的 C。我在标签中添加了它。我怎样才能让它更清楚?
  • @user628921:像 larsmans 更正:objective-c

标签: objective-c unit-testing singleton static-initializer


【解决方案1】:

将初始化代码放在共享实例方法中可能会更好

+(MySingleton *)shared
{
    static MySingleton *sharedInstance = nil;
    if(sharedInstance == nil){
        sharedInstance = [[MySingleton alloc] init];
    }
    return sharedInstance;
}

同样在您的代码中,您将一个对象与一个永远不会为真的类进行比较,而不是将 [self class] 与 [MySingleton class] 进行比较。

【讨论】:

  • OP 版本的优点是它是线程安全的。在像+initialize 这样的类方法中,self 是类。
【解决方案2】:

+initialize 中放置一个断点以确保该变量设置正确。如果这不能解释它,请在其上使用 watchpoint 以查看是谁在修改它。

【讨论】:

  • 我在调试器下尝试过,全局 gManager 初始化的唯一地方是在单元测试启动期间,使用以下调用堆栈`#0in +[AudioManager initialize] at AudioManager.m:118 #1in _class_initialize #2in _class_initialize #3in prepareForMethodLookup #4in lookUpMethod #5in _class_lookupMethodAndLoadCache #6in objc_msgSend #7in +[NSObject(SenTestRuntimeUtilities) senAllSubclasses] #8in +[SenTestSuite updateCache] #9in +[SenTestSuite suiteForBundleCache] #10in +[SenTestSuite testSuiteForBundlePath:] #11in + [SenTestProbe 指定TestSuite] #12in +[SenTestProbe runTests:]`
  • 那来自观察点?并且当时它被分配给了正确的类,但后来因为它是错误的类而崩溃?
  • 好的,发现问题了。我在应用程序关闭期间释放了我的单例 [[MySingleton sharedInstance] 发布]。如果稍后引用,则全局是运行时设置的随机实例。释放一个单例是没有意义的,但是我需要释放一些资源。所以我重构了代码。顺便说一句,我的代码在设备上运行良好,但单元测试多次调用应用关闭事件。
  • 很高兴它成功了。请记住,-dealloc 永远不会保证运行,并且通常在应用程序退出时会被跳过,因此如果您有需要释放的外部资源,则必须观察NSApplicationWillTerminate,或者安排由这样做的人调用。
猜你喜欢
  • 1970-01-01
  • 2014-08-25
  • 2017-09-10
  • 2013-09-22
  • 1970-01-01
  • 1970-01-01
  • 2019-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多