在我的适用于iOS 7.1的ARC应用程序中,我有一个单例类,其NSMutableDictionary
(属性为nonatomic, retain
),其中键是一个字符串,值为NSMutableArray
。该类在NSOperation
子类的回调中设置此字典。一切似乎工作得很好,直到一段时间后(可能是几分钟或几个小时),NSMutableDictionary
中的对象消失了。通常应用程序在后台并被带到前台,但几乎不可能找到可重现的测试用例。然而,这个问题一直在发生。
我该如何调试?我已经看到了发现泄漏的工具,但没有发现任何过早释放的工具。
CODE:
@interface MyManager : NSObject
@property (nonatomic, retain) NSOperationQueue * queue;
@property (nonatomic, retain) NSMutableDictionary * allObjectsByCategory;
@property (nonatomic, retain) NSMutableDictionary * allObjectsByName;
+ (MyManager *)default;
- (void)loadWithCompletion:(void (^)(BOOL succeeded))aBlock;
@end
@implementation MyManager
@synthesize queue, allObjectsByCategory, allObjectsByName;
- (void)loadWithCompletion:(void (^)(BOOL succeeded))aBlock {
self.queue = [[NSOperationQueue alloc] init];
MyFetchObjectsOperation * op = [[MyFetchObjectsOperation alloc] init];
op.successBlock = ^(NSMutableDictionary * allByCategory, NSMutableDictionary * allByName) {
self.allObjectsByCategory = allByCategory;
self.allObjectsByName = allByName;
aBlock(YES);
};
op.failureBlock = ^(NSError * err) {
aBlock(NO);
};
[self.queue addOperation:op];
}
@end
答案 0 :(得分:2)
您必须从班级中分配内存
- (void)loadWithCompletion:(void (^)(BOOL succeeded))aBlock {
self.queue = [[NSOperationQueue alloc] init];
MyFetchObjectsOperation * op = [[MyFetchObjectsOperation alloc] init];
op.successBlock = ^(NSMutableDictionary * allByCategory, NSMutableDictionary * allByName) {
self.allObjectsByCategory = [[NSMutableDictionary alloc] initWithDictionary:allByCategory];
self.allObjectsByName = [[NSMutableDictionary alloc] initWithDictionary:allByName];
aBlock(YES);
};
op.failureBlock = ^(NSError * err) {
aBlock(NO);
};
[self.queue addOperation:op];
}
答案 1 :(得分:1)
我觉得启用Zombies将是调试它的最佳方法,并找出对象过早发布的原因。这是zombie对象的作用(引自apple docs):
“用”僵尸“对象替换已释放的对象,该对象捕获任何使用它的尝试。当您向僵尸对象发送消息时,运行时会记录错误并崩溃。您可以查看回溯以查看链接触发僵尸探测器的电话。“
要启用Zombies,请按CMD + Shift +,(逗号),然后转到诊断选项卡并勾选“启用僵尸对象”
希望这有帮助!
答案 2 :(得分:0)
在我看来,您希望使用更持久的方式来存储此NSMutableDictionary
。将它存储在单例上并不能保证数据永远存在。只要为您的应用程序分配内存(实际上是您的单例本身)。当应用程序进入后台时,操作系统可以根据需要释放此内存(如@CodaFi所述)。
我建议您使用Core Data存储此数据,或将其保存到文件中以供日后阅读。还有其他选项(例如NSUserDefaults),但我可能必须更多地了解为什么要保留这些数据以真正了解最佳方法。
将此NSMutableDictionary
保存到文件的简单方法是使用以下代码:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *plistPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"myPlistFile.plist"];
[yourDictionary writeToFile:plistPath atomically:YES];
您可以使用以下代码检索数据(假设您使用从上方生成plistPath
的相同方式):
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
答案 3 :(得分:0)
也许你正在做类似的事情:
NSMutableDictionary *newDict = yourDictionary;
然后删除newDict
newDict = nil;
也会从yourDictionary
中删除值。