我有一个单例类,APIClient,它需要先设置userId和authToken才能调用我的后端。
我们目前正在NSUserDefaults中存储userId和authToken。对于全新安装,这些值不存在,我们在服务器中查询它们。
目前,我们在ViewControllers的viewDidLoad方法中有代码,如果这些值不存在,则手动查询服务器。
我有兴趣让这堂课“正常工作”。通过这个,我的意思是让客户端检查它是否已经初始化,如果没有激活对服务器的调用并设置适当的userId和authToken - 所有这些都没有人工干扰。
由于以下原因,这被证明是相当棘手的:
有没有人知道这个问题的好方法?
`
@interface APIClient ()
@property (atomic) BOOL initialized;
@property (atomic) NSLock *lock;
@end
@implementation APIClient
#pragma mark - Methods
- (void)setUserId:(NSNumber *)userId andAuthToken:(NSString *)authToken;
{
self.initialized = YES;
[self clearAuthorizationHeader];
[self setAuthorizationHeaderWithUsername:[userId stringValue] password:authToken];
}
#pragma mark - Singleton Methods
+ (APIClient *)sharedManager {
static dispatch_once_t pred;
static APIClient *_s = nil;
dispatch_once(&pred, ^{
_s = [[self alloc] initWithBaseURL:[NSURL URLWithString:SERVER_ADDR]];
_s.lock =[NSLock new] ;
});
[_s.lock lock];
if (!(_s.initialized)) {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSNumber *userId = @([prefs integerForKey:KEY_USER_ID]);
NSString *authToken = [prefs stringForKey:KEY_AUTH_TOKEN];
// If still doesn't exist, we need to fetch
if (userId && authToken) {
[_s setUserId:userId andAuthToken:authToken];
} else {
/*
* We can't have obtainCredentials to be a sync operation the OS will kill the thread
* Hence we will have to return nil right now.
* This means that subsequent calls after asyncObtainCredentials has finished
* will have the right credentials.
*/
[_s asyncObtainCredentials:^(NSNumber *userId, NSString *authToken){
[_s setUserId:userId andAuthToken:authToken];
}];
[_s.lock unlock];
return nil;
}
}
[_s.lock unlock];
return _s;
}
- (void)asyncObtainCredentials:(void (^)(NSNumber *, NSString *))successBlock {
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:SERVER_ADDR]];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:[OpenUDID value], @"open_udid", nil];
NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/get_user" parameters:params];
AFJSONRequestOperation *operation = \
[AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
...
// Do not use sharedManager here cause you can end up in a deadlock
successBlock(userId, authToken);
} failure:^(NSURLRequest *request , NSURLResponse *response , NSError *error , id JSON) {
NSLog(@"obtain Credential failed. error:%@ response:%@ JSON:%@",
[error localizedDescription], response, JSON);
}];
[operation start];
[operation waitUntilFinished];
}
答案 0 :(得分:2)
您应该在应用程序启动期间检查NSUserDefaults
中是否存在这些值。如果它们不存在,请拨打电话从服务器获取它并在屏幕上显示加载覆盖。获取后,您可以继续下一步。
如果你不想使用加载覆盖,你可以在isLoading
类中设置一些APIClient
标志,并检查是否仍然在提取asyn。因此,无论何时进行服务调用并且需要这些值,您都知道如何根据此标志处理它。获得所需值并存储在NSUserDefaults
后,即可继续执行下一步。您可以使用Notifications / Blocks / KVO通知您的viewcontrollers,让他们知道您已获取这些值。