2011-07-22 29 views
0

我想我的應用程序創建一個單用戶類,下面的代碼:幫助,單身的

#import "User.h" 
#import "Login.h" 
#import "SFHFKeychainUtils.h" 

// Constants 
static NSString* const kDBUserCurrentUserIDDefaultsKey = @"kDBUserCurrentUserIDDefaultsKey"; 

// Current User singleton 
static User* currentUser = nil; 

@implementation User 
@synthesize username = _username; 
@synthesize password = _password; 
@synthesize delegate = _delegate; 


- (id)init 
{ 
    self = [super init]; 
    if (self) { 
     // Initialization code here. 
    } 
    return self; 
} 

+ (NSString*)primaryKeyProperty { 
    return @"username"; 
} 

+ (User*)currentUser { 
    if (nil == currentUser) { 

     id username = [[NSUserDefaults standardUserDefaults] objectForKey:@"kApplicationUserNameKey"]; 
     if (!username) { 
      currentUser = [self new]; 
     } else{ 
      NSLog(@"CURRENT USER"); 
      return self; 
     } 

     [currentUser retain]; 
    } 

    return currentUser; 
} 

+ (void)setCurrentUser:(User*)user { 
    [user retain]; 
    [currentUser release]; 
    currentUser = user; 
} 

/** 
* Implementation of a RESTful login pattern. We construct an object loader addressed to 
* the /login resource path and POST the credentials. The target of the object loader is 
* set so that the login response gets mapped back into this object, populating the 
* properties according to the mappings declared in elementToPropertyMappings. 
*/ 
- (void)loginWithUsername:(NSString*)username andPassword:(NSString*)password delegate:(NSObject<DBUserAuthenticationDelegate>*)delegate { 
    _delegate = delegate; 

    //[RKObjectManager sharedManager].client.username = username; 
    //[RKObjectManager sharedManager].client.password = password; 

    self.username = username; 
    self.password = password; 

    RKObjectMapping * userMapping = [[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"LoginViewController"]; 
    [[RKObjectManager sharedManager] loadObjectsAtResourcePath:@"/account/verify.json" objectMapping:userMapping delegate:self]; 
} 

/** 
* Implementation of a RESTful logout pattern. We POST an object loader to 
* the /logout resource path. This destroys the remote session 
*/ 
- (void)logout/*:(NSObject<DBUserAuthenticationDelegate>*)delegate */{ 
    NSError * error = nil; 
    [[NSUserDefaults standardUserDefaults] setValue:nil forKey:@"kApplicationUserNameKey"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
    [SFHFKeychainUtils deleteItemForUsername:self.username andServiceName:@"convore" error:&error]; 

    NSLog(@"LOGGING OUT"); 
    if ([self.delegate respondsToSelector:@selector(userDidLogout:)]) { 
     [self.delegate userDidLogout:self]; 
    } 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"DBUserDidLogoutNotification" object:nil]; 
} 

- (void)loginWasSuccessful { 
    // Upon login, we become the current user 
    [User setCurrentUser:self]; 
    NSError * error = nil; 

    // Persist the username for recovery later 
    [[NSUserDefaults standardUserDefaults] setValue:self.username forKey:@"kApplicationUserNameKey"]; 
    [[NSUserDefaults standardUserDefaults] synchronize]; 
    [SFHFKeychainUtils storeUsername:self.username andPassword:self.password forServiceName:@"convore" updateExisting:TRUE error:&error]; 

    // Inform the delegate 
    if ([self.delegate respondsToSelector:@selector(userDidLogin:)]) { 
     [self.delegate userDidLogin:self]; 
    } 

    [[NSNotificationCenter defaultCenter] postNotificationName:@"DBUserDidLoginNotification" object:self]; 
} 

- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response 
{ 
    NSLog(@"Loaded payload: %@", [response bodyAsString]); 
} 

- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObject:(id)object 
{ 
    if ([objectLoader wasSentToResourcePath:@"/account/verify.json"]) { 
     Login * login = (Login *) object; 
     if ([login.username length] > 0) 
      [self loginWasSuccessful]; 
    } 
} 


- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError*)error { 
    if ([objectLoader wasSentToResourcePath:@"/account/verify.json"]) { 
     NSLog(@"Encountered an error: %@", error); 
     // Login failed 
     if ([self.delegate respondsToSelector:@selector(user:didFailLoginWithError:)]) { 
      [self.delegate user:self didFailLoginWithError:error]; 
     } 
    } 
} 

- (BOOL)isLoggedIn { 
    return self.username != nil; 
    //return self.singleAccessToken != nil; 
} 

- (void)dealloc { 
    _delegate = nil; 
    [_password release]; 
    [_passwordConfirmation release]; 
    [super dealloc]; 
} 

@end 

的問題是,每當我試圖訪問currentUser它總是打破了。我第一次叫loginWithUsernameandPassword,然後試圖調用currentUser,但是當我要求註銷的currentUser,它給了我一個錯誤:

調用此:

if ([[User currentUser] isLoggedIn]) 

給我:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[User isLoggedIn]: unrecognized selector sent to class 0x1a671c' 

似乎目前的用戶是零,這是爲什麼?

回答

4

快速辛格爾頓101(我希望我有這個,當我開始笑。只是每個人都向我指出這並沒有太大的幫助文檔)。單身的名稱將是「單身」

//Singleton.h 
#import <Foundation/Foundation.h> 

@interface SingletonManager : NSObject 
{ 
    NSDictionary* randomDictionary; //just using a dictionary for demonstrative purposes. You can make this a string or whatever you want. 
} 

+ (Singleton*)sharedSingleton; 

@property (nonatomic, retain) NSDictionary *randomDictionary; 

@end 

而且現在的.m

//Singleton.m 
#import "Singleton.h" 

static Singleton *sharedSingleton = nil; 

@implementation Singleton 

@synthesize randomDictionary; 

#pragma mark Singleton Method 
+ (Singleton*)sharedSingleton 
{ 
    @synchronized(self) 
    { 
     if(sharedSingleton == nil) 
     { 
      sharedSingleton = [[super allocWithZone:NULL] init]; 
     } 
    } 
    return sharedSingleton; 
} 
@end 

並設置/獲取,首次導入的單身在任何你需要的類:#import "Singleton.h",然後用Singleton *singletonManager = [Singleton sharedSingleton];抓住單身人士,然後根據需要做任何你需要的事情。即獲得您可以稱爲NSDictionary的描述[[singletonManager randomDictionary] description];

現在,這是使用ARC,所以如果你不是你,你只需要確保你正確地管理你的記憶。請享用。

+0

如果它使用MRC這將是在你的代碼的區別? – adit

+0

@Adit:你只需要dealloc等所有正常的東西。 ;) 祝你好運! – Baub

2

你是不是正確編碼的單。

+ (User *) currentUser { 
    @synchronized (self) { 

     if (currentUser == nil) { 
      currentUser = [[self alloc] init]; 
     } 
     return currentUser; 
    } 
} 
+0

好點,但這是如何解決OP的問題? – Perception

+0

爲什麼我在迴歸自我,不兼容的指針類型從結果類型用戶* – adit

+0

回報currentUser而不是自我函數返回「類」得到一個警告。 –

2

您需要先獲取單例對象,然後才能調用它的方法。

if ([[User currentUser] isLoggedIn]) { 
    // Magic happens here 
} 
+0

我這樣做了..這就是錯誤的地方 – adit

+0

@adit - 檢查你的代碼在哪裏進行調用,因爲編譯器非常清楚地告訴你,你正在嘗試使用實例方法作爲類方法 - 在這裏: '+ [User isLoggedIn]' – Perception

+0

我需要檢查什麼?如果你看到我上面的更新後,你可以看到我做了什麼,以產生錯誤 – adit

0

答案真的是來自XCodeDev和Matthieu Cormier的兩個答案的組合。您需要像代碼示例所說的那樣「保護」init,以便不創建對象的新版本。否則,它不是一個真正的More info on Singleton pattern.

而且,僅僅因爲它是一個單身並不意味着你可以只用類方法初始化之後訪問它。您仍然需要獲取初始化的實例,否則無法執行只需要實例中的某些值的操作。