我在 Objective-C .m 文件的全局范围内定义的 static
变量的行为出现问题。具体来说,我看到同一代码中的同一变量引用了不同的对象实例,具体取决于从 XCTest 目标执行时的范围。
.m 文件中定义的全局静态变量在主目标和 XCTest 目标之间的行为如何?这是我遇到的问题的示例:
设置代码
经理.m
#import "Manager.h"
// This is the variable of interest!
static Manager *sharedManager = nil;
@implementation Manager
+ (instancetype)sharedManager
{
return sharedManager;
}
+ (void)setManager:(Manager *)manager
{
sharedManager = manager;
}
@end
这是一个非常简单的ViewController
:
- (void)viewDidLoad {
[super viewDidLoad];
Manager *tempManager = [[Manager alloc] init];
[Manager setManager:tempManager];
}
困惑的根源
我正在尝试编写利用 Manager
的 XCTest 单元测试。问题是,我在同一代码执行流程中看到 不同 Manager
实例,具体取决于代码的上下文。这对我来说是全新且奇怪的。例如,考虑这个单元测试:
- (void)testManager {
// 1
ViewController *vc = [[ViewController alloc] init];
// 2
NSLog(@"manager %@", [Manager sharedManager]);
Manager *tempManager = [[Manager alloc] init];
[Manager setManager:tempManager];
// 3
NSLog(@"manager %@", [Manager sharedManager]);
[vc viewDidLoad];
// 4
NSLog(@"manager %@", [Manager sharedManager]);
}
以下是一些观察到的行为:
- 在第 1 行处断点暂停。如果我
po [Manager sharedManager]
,我将看到一个带有内存地址的 n 对象实例。我假设这是因为ViewController
是项目 Storyboard的初始 View Controller ,而viewDidLoad()
创建并设置第一个Manager
共享实例。 - 此行将 null 打印到控制台,这很奇怪,因为 1 上的断点和 po 在控制台中显示了实际对象。
- 此行打印一个实际的对象实例,但与第 1 行不同实例。有趣的是,如果我在这一行中断,则会出现
[po Manager sharedManager]
打印的对象实例与此行打印的 NSLog 不同,但与 1 处断点处打印的实例相同。 viewDidLoad()
运行并创建一个新的Manager
。使用po
中断此行会显示一个新实例,但NSLog
会打印与 3 相同的实例。
要点 通常,NSLog
对象的内存地址与调试器 po
对象不同。我不知道为什么。我猜这与 XCTest 在不同“应用程序”实例中的执行方式有关?
我观察到的行为是,在同一代码流中,.m 文件中的 static
全局变量的访问会根据访问它的文件而有所不同。为什么?
我在 GitHub 上发布了一个功能齐全、简单的项目来演示这一点:https://github.com/obuseme/TestStatic
最佳答案
当我尝试在新项目中手动重现问题时,我得到:
- 通过加载初始 View Controller 创建的管理器。 (顺便说一句,这是一个测试气味,因为测试应该完全控制其环境。对于单元测试,我使用 separate application delegate 来防止这种情况发生。)
- 登录的是同一个经理。
临时管理器
。- 由
viewDidLoad
设置的管理器。
这符合预期。您的不同结果表明您的项目设置中有一些奇怪的东西。然后我下载了你的项目并复制了你所描述的内容。日志中出现一条重要警告:
objc[5304]: Class Manager is implemented in both /Users/jorei/Library/Developer/CoreSimulator/Devices/BEEDA9FD-5FDA-4347-8691-FD80B8C7A18D/data/Containers/Bundle/Application/020A6698-99B6-472A-8E77-330CBCB5AA1A/TestStatic.app/TestStatic and /Users/jorei/Library/Developer/Xcode/DerivedData/TestStatic-clulxcackwiypobvsqvfatqiznvi/Build/Products/Debug-iphonesimulator/TestStatic.app/PlugIns/TestStaticTests.xctest/TestStaticTests. One of the two will be used. Which one is undefined.
问题是这样的:
Manager.m 出现两次。每个都有自己的 sharedManager
静态变量副本。
关于ios - 静态变量在多个目标之间的行为如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38616990/