在previous question的答案中,我学会了如何有效地创建我所描述的缓存单例对象:任何时候只有一个存在,但如果它& #39;不需要,它已被解除分配。
为了测试它,我写了这个单元测试:
- (void)testThingInstance {
MyThing *thing1 = [MyThing new];
MyThing *thing2 = [MyThing new];
XCTAssertEqual(thing1, thing2, @"Should have single thing");
// Let's release the thing, but keep its address.
uintptr_t pointer_as_integer = (uintptr_t)thing1;
thing1 = thing2 = nil;
// Now get a new thing. It should be a brand new object.
thing1 = [MyThing new];
XCTAssertNotEqual(
(uintptr_t)thing1, pointer_as_integer,
@"Should have a new thing, not a permanent singleton"
);
}
问题是,失败的是最后一次断言失败了一半。我将NSLog()
调用放在我的代码中的不同位置,以确保在释放其他两个引用之后实际上分配了一个新对象。我唯一可以猜到的是编译器注意到最近释放了大小合适的内存空间,因此决定使用它。即使我坚持使用代码来尝试在其间分配其他东西,它仍然经常使用相同的内存地址。
有什么方法可以让我不这样做吗?或者,最好是否有更好的方法来确保分配新对象而不是比较内存地址?
答案 0 :(得分:0)
我使用稍微不同的单例定义进行操作:它不仅一次只是一个对象,而是整个应用程序执行的单个对象。我不希望将其解除分配。
但是我能想到实现你所要做的唯一方法就是让单身人士在dealloc上假装自己的死亡,然后在下一次分配时把事情做好。
static MyThing *_zombieInstance;
- (void)dealloc {
_zombieInstance = self;
}
......然后,在创建一个新的:
+ (MyThing *)newMyThing {
MyThing *thing = [MyThing new]; // assuming you implement single-ness somehow here
_zombieInstance = nil;
return thing;
}
答案 1 :(得分:0)
好的,我已经提出了一种方法来实现它,而无需通过添加注入属性的类来修改缓存类的源。在MyThingTests.m
中,我将其添加到顶部:
#import <objc/runtime.h>
@interface MyThing (ioThingTest)
@property (nonatomic, strong) NSObject *sentinel;
@end
@implementation MyThing (ioThingTest)
- (NSObject *)sentinel {
return objc_getAssociatedObject(self, @selector(sentinel));
}
- (void)setSentinel:(NSObject *)value {
objc_setAssociatedObject(
self, @selector(sentinel), value,
OBJC_ASSOCIATION_RETAIN_NONATOMIC
);
}
@end
注入名为sentinel
的属性。当然,它仅在测试中可用。使用它,测试变为:
@implementation MyThingTests
- (void)testThingInstance {
MyThing *thing1 = [MyThing new];
thing1.sentinel = NSNull.null;
MyThing *thing2 = [MyThing new];
XCTAssertEqual(thing2.sentinel, thing1.sentinel, @"Should have single thing");
// Let's force a release.
thing1 = thing2 = nil;
// Now get a new thing. It should be a brand new object with no sentinel.
thing1 = [MyThing new];
XCTAssertNil(thing1.sentinel, @"Should have a new thing with no sentenel");
}
@end
所以我能够通过sentinel
属性的存在或不存在来创建一个新对象。