Одиночная проблема памяти объекта в цели c - PullRequest
0 голосов
/ 23 февраля 2012

Я застрял на этом некоторое время, и любые советы будут с благодарностью.Я создал одноэлементный объект SharedUser, который представляет пользователя, который в данный момент использует приложение.Этот объект SharedUser имеет две строки NSStrings (для имени пользователя и userId) и NSArray (для отделов компании, к которым принадлежит пользователь).Пользователь инициализируется при входе в систему методом initWithUsername.Внутри этого метода имя пользователя используется для анализа пользователя и получения уникального идентификационного номера пользователя и отделов пользователя.

Моя проблема заключается в следующем: когда я получаю пользователя с помощью метода sharedUser на более позднем этапеприложение, строка userId пуста и вызывает ошибку exc_bad_access, когда я пытаюсь ее использовать.Я знаю, что строка userId инициализируется, потому что я наблюдал, как это происходит в отладчике.Однако, как ни странно, строка имени пользователя все еще существует для того же объекта, в котором отсутствует строка userId.Я очень смущен тем, как можно освободить память, стоящую за userId, в то время как имя пользователя все еще будет зависать.

Мой класс SharedUser выглядит следующим образом:

@implementation SharedUser
@synthesize userId;
@synthesize username;
@synthesize departmentIds;

static SharedUser *sharedUser = nil;

+(SharedUser *)sharedUser {

@synchronized(self) {
        if (!sharedUser) {
            sharedUser=[[self alloc] init];
        }
    }
    return sharedUser;
}

+ (id)allocWithZone:(NSZone *)zone {
    @synchronized(self) {
        if (sharedUser == nil) {
             sharedUser = [super allocWithZone:zone];
             return sharedUser;
        }
    }

    return nil;
}

- (id)copyWithZone:(NSZone *)zone {
    return self;
}


- (id)retain {
    return self;
}


- (unsigned)retainCount {
    return NSUIntegerMax;
}


- (oneway void)release {
    // never release
}


- (id)autorelease {
    //do nothing
}


- (id) init {
    @synchronized(self) {
        [super init];
        username = @"";
        userId = @"";
        departmentIds = nil;
        return self;
    }
}


- (void) initWithUserName:(NSString *) loginName {

    username = loginName;

    //create a request and a connection    
    NSURL *url = [NSURL URLWithString:@"http://blah.com/url/for/the/json/"];   
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
    [request startSynchronous];
    NSError *error = [request error];

    if (!error) { 
        NSString *responseString = [request responseString];
        NSArray *listOfPeopleDictionaries = [responseString JSONValue];

        for (NSDictionary *personDictionary in listOfPeopleDictionaries) {
             if ([loginName isEqualToString:[personDictionary  objectForKey:@"username"]]) {
                // Set the user id
                userId = [personDictionary objectForKey:@"id"];

                // Set the user's department
                NSArray *departmentsArray = [personDictionary objectForKey:@"organizations"];
                for (NSDictionary *department in departmentsArray) {
                    [departmentIds addObject:[department objectForKey:@"id"]];
                }
             }
         }
     }
     else {
        //give error
     }
 }

- (void)dealloc {
    // Should never be called
    [username release];
    [userId release];
    [departmentIds release];
    [super dealloc];
}

Следующий код может вызвать ошибку exc_bad_access в третьей строке.

SharedUser *user = [SharedUser sharedUser];
NSLog(@"%@", user.username);
NSLog(@"%@", user.userId);

Тем не менее мой вопросгде память за освобождаемой строкой userId и что мне делать, чтобы это исправить?Я новичок в стеке переполнения, поэтому, пожалуйста, будьте осторожны.

Ответы [ 2 ]

0 голосов
/ 23 февраля 2012

Я бы, вероятно, выбрал другое решение: «нормальный» класс, который предлагает один общий экземпляр, но при этом не заботится обо всем (не) управлении памятью

И я хочу предложить новый грандиозный центральный диспетчерский подход

@implementation User
@synthesize userId;
@synthesize username;
@synthesize departmentIds;

+ (User *)sharedUser {
    static User *_sharedUser = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedUser = [[self alloc] init…];
        //what ever is needed to get a proper shared user
    });
    return _sharedUser;
}

@end

Больше не нужно, если вы согласны с менее строгой версией синглтона.

Это также намного проще в модульном тестировании.

User *sharedUser = [User sharedUser];

чтобы исправить свой код, попробуйте

username = [loginName copy];  //or retain, if you use retain in ur property

вместо

username = loginName;
0 голосов
/ 23 февраля 2012

userId не сохраняется вашим синглтоном. Значение принадлежит personDictionary, который принадлежит listOfPeopleDictionaries, который является автоматически возвращаемым значением из [responseString JSONValue]. При очистке пула автоматического выпуска вся цепь освобождается, включая userId.

Решение состоит в том, чтобы сохранить идентификатор пользователя, выполнив

userId = [[personDictionary objectForKey:@"id"] retain];

или

self.userId = [personDictionary objectForKey:@"id"]

username имеет ту же проблему, но, вероятно, не дает сбоя, так как вы держитесь за нее в объекте, который вызывает initWithUserName:.

...