我使用ARC构建了一个简单的琐事游戏。在使用Xcode中的Allocations分析工具分析其内存使用情况时,我发现内存并不总是被释放。对于问题的一个示例,我有一个ActivePlayer对象的类:
ActivePlayer.h:
@interface ActivePlayer : NSObject
@property (nonatomic, strong) NSString * name;
@property (nonatomic) NSInteger overallScore;
@property (nonatomic) NSInteger questionScore;
- (id) initWithName:(NSString *)name;
@end
ActivePlayer.m:
#import "ActivePlayer.h"
@interface ActivePlayer ()
@end
@implementation ActivePlayer
- (id) initWithName:(NSString *)name
{
self = [self init];
if (self) {
self.name = name;
self.overallScore = 0;
}
return self;
}
/*
- (void)dealloc
{
self.name = nil;
}
*/
@end
ActivePlayer是在ActiveGame类的createPlayer方法中创建的:
[[ActivePlayer alloc] initWithName:name]
我正在执行以下测试用例:我开始一个新游戏(分配一个ActivePlayer),我回答一个问题,然后游戏结束(此时ActivePlayer被解除分配)。然后我可以开始另一个游戏并重复这个循环(每个循环是一个“游戏”,如下所述)。在使用Allocations性能分析工具时,我期望看到的是内存已经在游戏中分配,但在游戏结束后已经解除分配(无论我玩多少次游戏)。但我发现情况并非总是如此:
BTW:下面的每个项目符号行描述了“分配”工具的“对象列表”选项卡中的一行;这个网站不会让我发布截图,因此文字描述。所有行都是Live;我只查看创建和静止分配。
在游戏#1正在进行中时,我看到以下分配。
比赛#1完成后,我看到以下内容。 ActivePlayer对象已被释放,但48字节仍然是Live。
如果我开始游戏#2,我会在游戏进行过程中看到以下内容。除了来自游戏#1的那个之外,还有两个新的分配。
在第2场比赛结束后,我看到以下内容。同样,ActivePlayer对象已被解除分配,但“Malloc X字节”分配仍然存在。
之后,我得到了不寻常的结果 - 如果我玩游戏#3,#4和#5,我从未在Category =“Malloc X Bytes”中看到游戏内行,只有Category = ActivePlayer的新行,游戏结束后释放。如上所示,前两个“Malloc”行继续存在。我还看到了其他奇怪的行为 - 在昨天使用iPhone 6.0模拟器进行测试时,实时内存仅在游戏#2和#3之后留下,但不是游戏#1,#4和#5。因此,虽然内存仍然是分配的,但它出现的时间似乎因我的设备和不同版本的模拟器而异。
我的问题:
注意:
答案 0 :(得分:3)
您列出的代码很好。看起来您仍然在代码中的其他位置维护对原始ActivePlayer的引用。
作为旁注,您创建ActivePlayer的模式不是常态 - 通常一个类不会在init方法中调用alloc。相反,调用者应该执行:
[[ActivePlayer alloc] initWithName:@"Bob"];
并且您的init方法应该使用
的返回值[super init];
答案 1 :(得分:2)
我觉得很奇怪你的构造函数是静态的(+符号)。命名约定要求名称前缀为init
的方法将返回托管内存对象。我怀疑内部方法的结果是根据其方法名称进行评估的。
答案 2 :(得分:1)
我认为实例计数测试确定您的代码没有泄漏ActivePlayers。顺便说一句,构造函数和inits上的更好的形式是这样的:
// .h
@interface ActivePlayer : NSObject
+ (id)activePlayerWithName:(NSString *)name;
@end
// .m
+ (id)activePlayerWithName:(NSString *)name {
return [[self alloc] initWithName:name];
}
// if you want to make this public (include in .h interface) you can
// the callers will have the choice of alloc init pattern, or the factory
//
- (id)initWithName:(NSString *)name {
self = [self init];
if (self) {
_name = name;
}
return self;
}
然后来电者这样做:
ActivePlayer *activePlayer = [ActivePlayer activePlayerWithName:@"Charlie"];