[CFDictionary objectForKey:]: сообщение отправлено на освобожденный экземпляр - PullRequest
0 голосов
/ 12 сентября 2011

После поиска в Интернете без какой-либо информации, я решил опубликовать здесь свою проблему, надеясь, что кто-то может объяснить, что не так с следующим фрагментом кода. Я просто не смог реализовать шаблон проектирования Singleton в 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 Тест [7837: b603] - [CFDictionary objectForKey:]: сообщение отправлено освобожденному экземпляру 0x4d565e0 *

И след памяти:

(gdb) info malloc-history 0x5c73300 Alloc: адрес блока: 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

Может кто-нибудь объяснить, что здесь происходит? Я действительно не понимаю, почему во второй раз я не могу получить доступ к словарю. Я не вижу ничего, что освобождает словарь во второй раз, когда он используется.

Спасибо всем,

аа

1 Ответ

5 голосов
/ 12 сентября 2011
    factors = [NSDictionary dictionaryWithContentsOfFile:path];

Вы устанавливаете переменную экземпляра для объекта с автоматическим освобождением.Как только пул будет очищен, следующее сообщение к factors, вероятно, пойдет BOOM .

Метод следует стандартным правилам для каждого метода в API-интерфейсах платформы.См. Руководство по политикам .

. Документация идет очень долго, чтобы не повторять общие правила для каждого метода;то есть, если вы не читаете руководства, вы не поймете, как обязательно работает каждый отдельный метод.

Это "дай человеку рыбу, он съест на один день ... научичеловек ловить рыбу, и он накормит себя на всю жизнь ".

...