【问题标题】:Multiple static libraries, swizzling and dispatch_once多个静态库,swizzling 和 dispatch_once
【发布时间】:2014-01-07 20:26:03
【问题描述】:

我有一个主应用程序,我们称之为 App
它链接两个静态库StatLib1StatLib2
StatLib1链接StatLib2 图书馆。

如您所见,StatLib2 库被链接了两次。


StatLib2 库的一个类别中,我正在做一些调整:

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"test");

        [self itk_swizzleInstanceMethodWithSelector:@selector(someMethod:)
                                    withNewSelector:@selector(itk_someMethod:)];
    });
}

test 被记录了两次,这意味着方法将被调回原来的状态。
我确定这是问题所在,因为当我删除 App 目标上的 StatLib2 链接时,不会发生这种情况。


  1. 首先,为什么会发生这种情况?
  2. 如何在不删除 App 目标上的 StatLib2 链接的情况下解决此问题?

【问题讨论】:

  • 为什么将 StatLib1 与 StatLib2 链接起来?将最终的可执行文件与所有静态库链接就足够了(以正确的顺序)。
  • @MartinR StatLib1 在不同的存储库中,也应该在不同的项目中使用。例如单元测试,这意味着我必须将单元测试目标与 StatLib1 链接起来。确定是这样的吗?
  • 我对单元测试没有太多经验,但一般来说,所有静态库都是在链接可执行文件时指定的。 - 实际上,您不能将一个静态库链接到另一个静态库。也许 StatLib1 包含 StatLib2 的副本。你应该在 load 方法中 NSLog(@"test: %p", self) 看看你是否有两个不同的类实例加载到应用程序中。
  • @MartinR +load 在加载类时被调用。它不是一个实例,它是一个类方法。我将 StatLib1Statlib2 链接的方式与将 AppStatlib2 链接的方式相同。
  • 是的,但我目前的猜测(我可能完全错了)您正在加载该类的两个独立副本。请尝试按照上面的建议记录类指针。 - 或者更好:NSLog(@"test: class=%p, token=%p", self, &onceToken)

标签: iphone objective-c macos cocoa-touch cocoa


【解决方案1】:

首先,静态库只是目标文件的存档,所以 您不能真正链接一个静态库与另一个静态库。 可能发生的情况是 StatLib2 的所有对象都复制StatLib1。稍后,当应用程序链接时,StatLib2 的另一个副本 被添加到可执行文件中。

所以你以load 方法的两个“实例”结束,每个实例都有自己的 static dispatch_once_t onceToken。这两个方法都在类时调用 已加载,并且每个都执行自己的 dispatch_once() 块。

的输出也显示了这一点
NSLog(@"test: class=%p, token=%p", self, &onceToken)

test: class=0x7fff7c76cdc8, token=0x100021f60
test: class=0x7fff7c76cdc8, token=0x100021f98

类是相同的(因为它是同一个类的一个类别),但是 onceToken 不同。

作为一种解决方案,您应该只将最终可执行文件链接到两者 静态库。

【讨论】:

  • 不错的分析!这里有点晚了;并希望这不会超出范围:您能否分享一个链接,我可以在其中了解更多有关将最终 .exe 链接到多个静态库的信息,以避免出现多个单例?谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多