Search code examples
objective-cmultithreadingios5singletonatomic

Thread-safe singleton and nonatomic properties issue


I have an issue, described below and solution. But I think our solution is not really "right way" to solve this issue.

1: I have thread safe singleton for Data

//DataSingleton.h
@interface DataSingleton : NSObject
@property (nonatomic, readonly, retain) NSString *userLogin;
-(void)setPrettyLogin:(NSString*)prettyLogin;
@end

and

//DataSingleton.m
#import "DataSingleton.h"

@synthesize userLogin   = _userLogin;

+(id)sharedSingleton{

    static dispatch_once_t DataSPred;
    static DataSingleton *shared = nil;
    dispatch_once(&DataSPred, ^{ shared = [[self alloc] init]; });
    return shared;
}

-(void)setPrettyLogin:(NSString*)prettyLogin{
    _userLogin = prettyLogin;
}

@end

2: Also I have same singleton for Network and i use feature

[NSURLConnection sendAsynchronousRequest:request 
     queue:[NSOperationQueue mainQueue] 
     completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) 
         { <block> }];
// I know about mainQueue - only for UI. Here it is, for clarity.

3: The issue

When i try get [[DataSingleton sharedSingleton] userLogin] within NSURLConnection block (in one of NetworkSingleton methods) - i get same time and in _userLogin i found some garbage =(

4:Bad solution

I spend about an hour and don't find correct answer for my question. And create this:

//DataSingleton.h
@interface DataSingleton : NSObject{
    NSString* _userLogin;
}

-(NSString*)userLogin;
-(void)setPrettyLogin:(NSString*)prettyLogin;
@end

and

//DataSingleton.m
#import "DataSingleton.h"

+(id)sharedSingleton{

    static dispatch_once_t DataSPred;
    static DataSingleton *shared = nil;
    dispatch_once(&DataSPred, ^{ shared = [[self alloc] init]; });
    return shared;
}

-(NSString*)userLogin{
    return _userLogin;
}

-(void)setPrettyLogin:(NSString*)prettyLogin{

    _userLogin = [prettyLogin retain];
    //I can,t release it and 
    //static code analysis is not happy with what is happening
}

@end

Are any one have the idea?

Best regards Sergey


Solution

  • You have to retain the value in the setter. Actually the problem has nothing to do with threading.

    Your function is almost correct.

    -(void)setPrettyLogin:(NSString*)prettyLogin {
        _userLogin = [prettyLogin retain];
    }
    

    But it should be

    -(void)setPrettyLogin:(NSString*)prettyLogin {
        if (_userLogin != prettyLogin) {
             NSString *tmp = _userLogin;
             _userLogin = [prettyLogin retain];
             [tmp release];
        } 
    }
    
    -(void)dealloc {
        [_userLogin release];
        [super dealloc];
    }
    

    Now if you wan't to release the value call

    [[DataSingleton sharedSingleton] setPrettyLogin:nil];