[CFDictionary objectForKey:]:发送到已释放实例的消息
在没有任何见解的情况下在网络上搜索后,我决定在这里发布我的问题,希望有人能够解释以下代码有什么问题。我只是无法在 Objective-C 中实现单例设计模式。我在互联网上找到了一些实现该模式的代码,并对它进行了一些修改以添加从 plist 文件启动的字典(其中属性列表中的每个条目本身就是一个字典):
@interface UnitManager : NSObject {
NSString *someProperty;
NSDictionary *factors;
}
@property (nonatomic, retain) NSString *someProperty;
@property (nonatomic, retain) NSDictionary *factors;
+ (id) sharedUnitManager;
@end
// implementation file
#import "Unit.h"
#define MARGIN 20
static UnitManager *unitManager = nil;
@implementation UnitManager
@synthesize someProperty;
@synthesize factors;
#pragma mark Singleton Methods
+ (id)sharedUnitManager {
@synchronized(self) {
if(unitManager == nil)
unitManager = [[super allocWithZone:NULL] init];
}
return unitManager;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedUnitManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
// never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
// get path to file that stores category order
NSString *path = [[NSBundle mainBundle] pathForResource:@"factors" ofType:@"plist"];
factors = [NSDictionary dictionaryWithContentsOfFile:path];
}
return self;
}
- (void)dealloc {
// Should never be called, but just here for clarity really.
[someProperty release];
NSLog(@"should NEVER GET HERE!");
[factors release];
[super dealloc];
}
@end
然后,稍后我尝试一些代码访问单例对象中的字典,第一次调用它工作正常,但第二次它访问已释放的内存!
- (void) someFunction {
...
NSString *str = [[[[UnitManager sharedUnitManager] factors] objectForKey:category] objectForKey:name];
...
...
}
我收到的消息是
2011-09-12 17:39:44.567 Test[7837:b603] -[CFDictionary objectForKey:]: message sent to deallocated instance 0x4d565e0*
以及内存跟踪:
(gdb) info malloc-history 0x5c73300 分配:块地址:0x05c73300 长度:48 堆栈 - pthread: 0xac2bd2c0 帧数: 44
0. 0x92573993 in malloc_zone_malloc
1. 0xebe87d in _CFRuntimeCreateInstance
2. 0xebe47a in CFBasicHashCreate
3. 0xf81e44 in __CFDictionaryCreateTransfer
4. 0xeed3ff in __CFBinaryPlistCreateObject2
5. 0xee2009 in __CFTryParseBinaryPlist
6. 0xee1a48 in _CFPropertyListCreateWithData
7. 0xee19ba in CFPropertyListCreateWithData
8. 0xee194f in CFPropertyListCreateFromXMLData
9. 0x791e34 in _NSParseObjectFromASCIIPropertyListOrSerialization
10. 0x7913d5 in +[NSDictionary(NSDictionary) newWithContentsOf:immutable:]
11. 0xf067bf in -[__NSPlaceholderDictionary initWithContentsOfFile:]
12. 0x791308 in +[NSDictionary(NSDictionary) dictionaryWithContentsOfFile:]
13. 0xcb38 in -[UnitManager init] at Unit.m:54
14. 0xc833 in +[UnitManager sharedUnitManager] at Unit.m:25
15. 0xe03a in -[Unit factor] at Unit.m:226
16. 0x39c9 in -[MainViewController updateTextFields] at MainViewController.m:113
17. 0x4037 in -[MainViewController refresh] at MainViewController.m:229
18. 0x79c669 in _nsnote_callback
19. 0xf879f9 in __CFXNotificationPost_old
20. 0xf0693a in _CFXNotificationPostNotification
21. 0x79220e in -[NSNotificationCenter postNotificationName:object:userInfo:]
22. 0x79e551 in -[NSNotificationCenter postNotificationName:object:]
23. 0x62f7 in -[MainViewController changeUnit:] at MainViewController.m:447
24. 0x2a4fd in -[UIApplication sendAction:to:from:forEvent:]
25. 0xba799 in -[UIControl sendAction:to:forEvent:]
26. 0xbcc2b in -[UIControl(Internal) _sendActionsForEvents:withEvent:]
27. 0xba750 in -[UIControl sendActionsForControlEvents:]
28. 0xfa59b in -[UISegmentedControl setSelectedSegmentIndex:]
29. 0xff39d in -[UISegmentedControl touchesBegan:withEvent:]
30. 0x4ed41 in -[UIWindow _sendTouchesForEvent:]
31. 0x2fc37 in -[UIApplication sendEvent:]
32. 0x34f2e in _UIApplicationHandleEvent
33. 0x11e8992 in PurpleEventCallback
34. 0xf90944 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
35. 0xef0cf7 in __CFRunLoopDoSource1
36. 0xeedf83 in __CFRunLoopRun
37. 0xeed840 in CFRunLoopRunSpecific
38. 0xeed761 in CFRunLoopRunInMode
39. 0x11e71c4 in GSEventRunModal
40. 0x11e7289 in GSEventRun
41. 0x38c93 in UIApplicationMain
42. 0x2639 in main at main.m:14
43. 0x25b5 in start
有人能解释一下这里发生了什么吗?我实在不明白为什么第二次就不能查字典了。我没有看到任何东西会在第二次使用字典时释放它。
谢谢大家啊
aa
After searching the web without any insight, I decided to post my problem here hoping someone can explain what's wrong with the following piece of code. I just couldn't implement the singleton design pattern in Objective-C. I found some code that implements the pattern on the internet, and modified it a little bit to add a dictionary that is initiated from a plist file (where each entry in the property list is itself a dictionary):
@interface UnitManager : NSObject {
NSString *someProperty;
NSDictionary *factors;
}
@property (nonatomic, retain) NSString *someProperty;
@property (nonatomic, retain) NSDictionary *factors;
+ (id) sharedUnitManager;
@end
// implementation file
#import "Unit.h"
#define MARGIN 20
static UnitManager *unitManager = nil;
@implementation UnitManager
@synthesize someProperty;
@synthesize factors;
#pragma mark Singleton Methods
+ (id)sharedUnitManager {
@synchronized(self) {
if(unitManager == nil)
unitManager = [[super allocWithZone:NULL] init];
}
return unitManager;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedUnitManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
// never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
// get path to file that stores category order
NSString *path = [[NSBundle mainBundle] pathForResource:@"factors" ofType:@"plist"];
factors = [NSDictionary dictionaryWithContentsOfFile:path];
}
return self;
}
- (void)dealloc {
// Should never be called, but just here for clarity really.
[someProperty release];
NSLog(@"should NEVER GET HERE!");
[factors release];
[super dealloc];
}
@end
Then, some code later I try to access the dictionary in the singleton object, and the first time it's called works fine, but the second time it accesses deallocated memory!
- (void) someFunction {
...
NSString *str = [[[[UnitManager sharedUnitManager] factors] objectForKey:category] objectForKey:name];
...
...
}
The message I get is
2011-09-12 17:39:44.567 Test[7837:b603] -[CFDictionary objectForKey:]: message sent to deallocated instance 0x4d565e0*
And the memory trace:
(gdb) info malloc-history 0x5c73300
Alloc: Block address: 0x05c73300 length: 48
Stack - pthread: 0xac2bd2c0 number of frames: 44
0. 0x92573993 in malloc_zone_malloc
1. 0xebe87d in _CFRuntimeCreateInstance
2. 0xebe47a in CFBasicHashCreate
3. 0xf81e44 in __CFDictionaryCreateTransfer
4. 0xeed3ff in __CFBinaryPlistCreateObject2
5. 0xee2009 in __CFTryParseBinaryPlist
6. 0xee1a48 in _CFPropertyListCreateWithData
7. 0xee19ba in CFPropertyListCreateWithData
8. 0xee194f in CFPropertyListCreateFromXMLData
9. 0x791e34 in _NSParseObjectFromASCIIPropertyListOrSerialization
10. 0x7913d5 in +[NSDictionary(NSDictionary) newWithContentsOf:immutable:]
11. 0xf067bf in -[__NSPlaceholderDictionary initWithContentsOfFile:]
12. 0x791308 in +[NSDictionary(NSDictionary) dictionaryWithContentsOfFile:]
13. 0xcb38 in -[UnitManager init] at Unit.m:54
14. 0xc833 in +[UnitManager sharedUnitManager] at Unit.m:25
15. 0xe03a in -[Unit factor] at Unit.m:226
16. 0x39c9 in -[MainViewController updateTextFields] at MainViewController.m:113
17. 0x4037 in -[MainViewController refresh] at MainViewController.m:229
18. 0x79c669 in _nsnote_callback
19. 0xf879f9 in __CFXNotificationPost_old
20. 0xf0693a in _CFXNotificationPostNotification
21. 0x79220e in -[NSNotificationCenter postNotificationName:object:userInfo:]
22. 0x79e551 in -[NSNotificationCenter postNotificationName:object:]
23. 0x62f7 in -[MainViewController changeUnit:] at MainViewController.m:447
24. 0x2a4fd in -[UIApplication sendAction:to:from:forEvent:]
25. 0xba799 in -[UIControl sendAction:to:forEvent:]
26. 0xbcc2b in -[UIControl(Internal) _sendActionsForEvents:withEvent:]
27. 0xba750 in -[UIControl sendActionsForControlEvents:]
28. 0xfa59b in -[UISegmentedControl setSelectedSegmentIndex:]
29. 0xff39d in -[UISegmentedControl touchesBegan:withEvent:]
30. 0x4ed41 in -[UIWindow _sendTouchesForEvent:]
31. 0x2fc37 in -[UIApplication sendEvent:]
32. 0x34f2e in _UIApplicationHandleEvent
33. 0x11e8992 in PurpleEventCallback
34. 0xf90944 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
35. 0xef0cf7 in __CFRunLoopDoSource1
36. 0xeedf83 in __CFRunLoopRun
37. 0xeed840 in CFRunLoopRunSpecific
38. 0xeed761 in CFRunLoopRunInMode
39. 0x11e71c4 in GSEventRunModal
40. 0x11e7289 in GSEventRun
41. 0x38c93 in UIApplicationMain
42. 0x2639 in main at main.m:14
43. 0x25b5 in start
Can someone explain what is happening here? I really don't understand why the second time I can't access the dictionary. I don't see anything deallocating the dictionary for the second time it's used.
Thank you all,
aa
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您正在将实例变量设置为自动释放的对象。一旦池耗尽,发送给
factors
的下一条消息可能会BOOM。该方法遵循框架 API 中每个方法的标准规则。请参阅 政策指南。
该文档竭尽全力不重复每个方法的通用规则;也就是说,如果您不阅读指南,您将无法理解每种方法的工作原理。
这就是“授人以鱼,可食一日……授人以鱼,可食终生”的道理。
You are setting an instance variable to an autoreleased object. As soon as the pool is drained, the next message to
factors
will likely go BOOM.The method follows the standard rules for every method in the framework APIs. See the policies guide.
The documentation goes to great lengths to not repeat the common rules on a per method basis; i.e. if you don't read the guides, you won't understand how each individual method necessarily works.
It is a "give a man a fish, he'll eat for a day... teach a man to fish, and he'll feed himself for a lifetime" approach.