目标c中的单例对象内存问题

时间:2012-02-22 21:07:33

标签: objective-c cocoa-touch memory-management singleton exc-bad-access

我一直坚持这一点,任何建议都会非常感激。我创建了一个名为SharedUser的单例对象,它表示当前正在使用该应用程序的用户。此SharedUser对象具有两个NSStrings(用于username和userId)和一个NSArray(用于用户所属的公司部门)。使用名为initWithUsername的方法登录时初始化用户。在此方法中,用户名用于解析用户并获取用户的唯一ID号和用户的部门。

我的问题如下:当我在应用程序中稍后让用户通过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 :(得分:0)

您的单身人士不会保留

userId。该值归personDictionary所有,listOfPeopleDictionaries[responseString JSONValue]拥有,这是userId的自动释放返回值。清除自动释放池后,将释放整个链,包括userId = [[personDictionary objectForKey:@"id"] retain];

解决方案是通过执行

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

username

initWithUserName:有同样的问题,但可能没有崩溃,因为你在调用{{1}}的对象中坚持它。

答案 1 :(得分:0)

我可能会选择其他解决方案:“普通”类,它提供一个共享实例,而不会打扰所有内存(非)管理

我想提出新的宏观中央调度方法

@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;