我对Objective-C .m文件中全局范围中定义的static
变量的行为有疑问。具体来说,我从同一代码中看到同一个变量引用的对象的不同实例,具体取决于从XCTest目标执行时的范围。
.m文件中定义的全局静态变量如何在main和XCTest目标之间运行?以下是我看到的问题的一个例子:
Manager.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单元测试。问题是,我在相同的代码执行流程中看到{strong>不同的实例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]);
}
以下是一些观察到的行为:
po [Manager sharedManager]
我将看到一个带有内存地址的n对象实例。我假设这是因为ViewController
是项目故事板的初始视图控制器,viewDidLoad()
创建并设置了第一个Manager
共享实例。[po Manager sharedManager]
,则打印的对象实例不同于此行中的NSLog打印,但与断点处打印的实例相同。viewDidLoad()
运行会创建一个新的Manager
。使用po
打破此行会显示一个新实例,但NSLog
会将同一个实例打印为3。 重要事项 NSLog
'd对象的内存地址通常与调试器po
'd对象不同。我不知道为什么。我猜它与XCTest在不同的“app”实例中的执行方式有关吗?
我观察到的行为是,在同一代码流中,.m文件中static
全局变量的访问权限取决于访问它的文件。为什么呢?
我在GitHub发布了一个功能齐全,功能齐全的项目:https://github.com/obuseme/TestStatic
答案 0 :(得分:1)
当我尝试在一个新项目中手动重建问题时,我得到了:
tempmanager
。viewDidLoad
设置的经理。这是预期的。您的不同结果表明您的项目设置中存在一些奇怪的内容。然后我下载了你的项目并重现你所描述的内容。日志中会显示一条重要警告:
objc [5304]:类管理器在/ Users / jorei / Library / Developer / CoreSimulator / Devices / BEEDA9FD-5FDA-4347-8691-FD80B8C7A18D / data / Containers / Bundle / Application / 020A6698-99B6-472A中实现-8E77-330CBCB5AA1A / TestStatic.app / TestStatic和/Users/jorei/Library/Developer/Xcode/DerivedData/TestStatic-clulxcackwiypobvsqvfatqiznvi/Build/Products/Debug-iphonesimulator/TestStatic.app/PlugIns/TestStaticTests.xctest/TestStaticTests。将使用两者之一。哪一个未定义。
问题在于:
Manager.m有两次出现。每个都有自己的sharedManager
静态变量副本。