помочь с синглтоном - PullRequest
       4

помочь с синглтоном

0 голосов
/ 22 июля 2011

Я пытаюсь создать класс Singleton User в моем приложении, вот код:

#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'

кажется, что currentUser равен нулю, почему это так?

Ответы [ 4 ]

4 голосов
/ 22 июля 2011

Quick Singleton 101 (хотелось бы, чтобы у меня было это, когда я начал, смеются. Все просто указали мне на документы, которые не сильно помогли).Имя синглтона будет «Singleton»

//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, поэтому если вы этого не сделаете, вам просто нужно убедиться, что вы правильно управляете своей памятью.Наслаждайтесь.

2 голосов
/ 22 июля 2011

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

if ( [[User currentUser] isLoggedIn] ) {
  // Magic happens here
}
2 голосов
/ 22 июля 2011

Вы неправильно кодируете свой синглтон.

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

       if (currentUser == nil) {
            currentUser = [[self alloc] init];
       }
       return currentUser;
   }
}
0 голосов
/ 22 июля 2011

Ответ - это действительно комбинация двух ответов от XCodeDev и Matthieu Cormier. Вы должны «защитить» свой init так, как говорит пример кода, чтобы новые версии объекта не создавались. В противном случае это не реальный синглтон. Дополнительная информация о синглтон-паттерне.

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

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