Objective-C: 单例-class方法执行完后得到结果?
Objective-C: Get a result of a singleton-class method after finish executing the method?
我有一个单例 class 检查应用程序的登录状态。
单例 class 中有一个名为 attemptToLogin
的方法,它使用参数和 returns 使用 json 登录状态数据发出 http 请求。 (对或错)
现在主要 TabBarViewController
我做了以下事情:
@interface CustomTabBarController ()
@end
@implementation CustomTabBarController{
LoginCheckSingleton *loginSingleton;
dispatch_queue_t myCustomQueue;
}
-(void)viewDidAppear:(BOOL)animated{
myCustomQueue = dispatch_queue_create("com.myDomain.appName", NULL);
loginSingleton = [LoginCheckSingleton sharedInstance];
dispatch_sync(myCustomQueue, ^{
[loginSingleton attemptToLogin];
});
if([loginSingleton.loginstat isEqual: @"true"]){
NSLog(@"Logged In");
}else{
NSLog(@"Not Logged In");
[self performSegueWithIdentifier:@"goToLoginView" sender:self];
}
}
这里的dispatch_sync
没有正常工作,我想先执行dispatch_sync里面的函数,然后在执行它下面的if
语句之前得到结果。但是 if
语句是在 dispatch_sync 中的块完成之前执行的。
这是Singleton Class
:
#import "LoginCheckSingleton.h"
#import "AFNetworking.h"
#import "SSKeychain.h"
#import "CustomTabBarController.h"
static LoginCheckSingleton *sharedInstance = nil;
@interface LoginCheckSingleton (){
NSString *serverURLString;
NSURL *serverURL;
NSString *userId;
NSString *password;
NSString *email;
NSMutableArray *jsonContents;
NSMutableDictionary *dictionary;
NSString *loggedInStatus;
bool loggedInTF;
}
@end
@implementation LoginCheckSingleton{
}
+ (LoginCheckSingleton*) sharedInstance {
static dispatch_once_t _singletonPredicate;
static LoginCheckSingleton *_singleton = nil;
dispatch_once(&_singletonPredicate, ^{
_singleton = [[super allocWithZone:nil] init];
});
return _singleton;
}
+ (id) allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(void)attemptToLogin{
// Retrieve credentials from Keychain
userId = [SSKeychain passwordForService:@"com.lazemni.iFresh"
account:@"ifreshUserId"];
password = [SSKeychain passwordForService:@"com.lazemni.iFresh"
account:@"ifreshPassword"];
email = [SSKeychain passwordForService:@"com.lazemni.iFresh"
account:@"ifreshEmail"];
if(email == nil || password == nil){
NSLog(@"empty username or password");
}else{
NSLog(@"not empty username or password");
serverURLString = @"http://www.lazemni.com/demo/ifresh/api/login/";
serverURLString = [serverURLString stringByAppendingString:email];
serverURLString = [serverURLString stringByAppendingString:@"/"];
serverURLString = [serverURLString stringByAppendingString:password];
NSLog(@"%@",serverURLString);
serverURL = [NSURL URLWithString:serverURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:serverURL];
//AFNetworking asynchronous url request
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
jsonContents = [responseObject objectForKey:@"login"];
NSLog(@"%@",jsonContents);
dictionary = [jsonContents objectAtIndex:0];
loggedInStatus = [dictionary objectForKey:@"status"];
if([loggedInStatus isEqual: @"true"]){
NSLog(@"Succefully loggedin!");
[SSKeychain setPassword:[dictionary objectForKey:@"user_id"] forService:@"com.lazemni.iFresh" account:@"ifreshUserId"];
[SSKeychain setPassword:[dictionary objectForKey:@"email"] forService:@"com.lazemni.iFresh" account:@"ifreshEmail"];
[SSKeychain setPassword:[dictionary objectForKey:@"password"] forService:@"com.lazemni.iFresh" account:@"ifreshPassword"];
self.loginstat = @"true";
loggedInTF = true;
}else if([loggedInStatus isEqual: @"false"]){
NSLog(@"Wrong email/password combination!");
self.loginstat = @"false";
loggedInTF = false;
}
} failure:nil];
[operation start];
}
}
@end
我一直不明白 dispatch_sync 是如何运作的,
知道如何等待 [loginSingleton attemptToLogin];
完成吗?
attemptToLogin
大概是异步方法吧。您希望以这样的方式编写 attemptToLogin,以便在 HTTP 请求完成执行时为您提供回调。您可以通过完成块、委托或通知来做到这一点。
如果您等待请求完成,您将最终阻塞主线程,这将冻结用户交互,导致糟糕的用户体验。
- (void)attemptToLogin:(void(^)(BOOL login))complete {
...
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
....
// After you get login status
complete(your_login_status_here);
}
}
并且在CustomTabBarController
-(void)viewDidAppear:(BOOL)animated{
myCustomQueue = dispatch_queue_create("com.myDomain.appName", NULL);
loginSingleton = [LoginCheckSingleton sharedInstance];
[loginSingleton attemptToLogin:^(loginStatus){
if([loginStatus isEqual: @"true"]){
NSLog(@"Logged In");
}else{
NSLog(@"Not Logged In");
dispatch_async(dispatch_get_main_queue(), {
[self performSegueWithIdentifier:@"goToLoginView" sender:self];
});
}
}];
}
我有一个单例 class 检查应用程序的登录状态。
单例 class 中有一个名为 attemptToLogin
的方法,它使用参数和 returns 使用 json 登录状态数据发出 http 请求。 (对或错)
现在主要 TabBarViewController
我做了以下事情:
@interface CustomTabBarController ()
@end
@implementation CustomTabBarController{
LoginCheckSingleton *loginSingleton;
dispatch_queue_t myCustomQueue;
}
-(void)viewDidAppear:(BOOL)animated{
myCustomQueue = dispatch_queue_create("com.myDomain.appName", NULL);
loginSingleton = [LoginCheckSingleton sharedInstance];
dispatch_sync(myCustomQueue, ^{
[loginSingleton attemptToLogin];
});
if([loginSingleton.loginstat isEqual: @"true"]){
NSLog(@"Logged In");
}else{
NSLog(@"Not Logged In");
[self performSegueWithIdentifier:@"goToLoginView" sender:self];
}
}
这里的dispatch_sync
没有正常工作,我想先执行dispatch_sync里面的函数,然后在执行它下面的if
语句之前得到结果。但是 if
语句是在 dispatch_sync 中的块完成之前执行的。
这是Singleton Class
:
#import "LoginCheckSingleton.h"
#import "AFNetworking.h"
#import "SSKeychain.h"
#import "CustomTabBarController.h"
static LoginCheckSingleton *sharedInstance = nil;
@interface LoginCheckSingleton (){
NSString *serverURLString;
NSURL *serverURL;
NSString *userId;
NSString *password;
NSString *email;
NSMutableArray *jsonContents;
NSMutableDictionary *dictionary;
NSString *loggedInStatus;
bool loggedInTF;
}
@end
@implementation LoginCheckSingleton{
}
+ (LoginCheckSingleton*) sharedInstance {
static dispatch_once_t _singletonPredicate;
static LoginCheckSingleton *_singleton = nil;
dispatch_once(&_singletonPredicate, ^{
_singleton = [[super allocWithZone:nil] init];
});
return _singleton;
}
+ (id) allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
-(void)attemptToLogin{
// Retrieve credentials from Keychain
userId = [SSKeychain passwordForService:@"com.lazemni.iFresh"
account:@"ifreshUserId"];
password = [SSKeychain passwordForService:@"com.lazemni.iFresh"
account:@"ifreshPassword"];
email = [SSKeychain passwordForService:@"com.lazemni.iFresh"
account:@"ifreshEmail"];
if(email == nil || password == nil){
NSLog(@"empty username or password");
}else{
NSLog(@"not empty username or password");
serverURLString = @"http://www.lazemni.com/demo/ifresh/api/login/";
serverURLString = [serverURLString stringByAppendingString:email];
serverURLString = [serverURLString stringByAppendingString:@"/"];
serverURLString = [serverURLString stringByAppendingString:password];
NSLog(@"%@",serverURLString);
serverURL = [NSURL URLWithString:serverURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:serverURL];
//AFNetworking asynchronous url request
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
jsonContents = [responseObject objectForKey:@"login"];
NSLog(@"%@",jsonContents);
dictionary = [jsonContents objectAtIndex:0];
loggedInStatus = [dictionary objectForKey:@"status"];
if([loggedInStatus isEqual: @"true"]){
NSLog(@"Succefully loggedin!");
[SSKeychain setPassword:[dictionary objectForKey:@"user_id"] forService:@"com.lazemni.iFresh" account:@"ifreshUserId"];
[SSKeychain setPassword:[dictionary objectForKey:@"email"] forService:@"com.lazemni.iFresh" account:@"ifreshEmail"];
[SSKeychain setPassword:[dictionary objectForKey:@"password"] forService:@"com.lazemni.iFresh" account:@"ifreshPassword"];
self.loginstat = @"true";
loggedInTF = true;
}else if([loggedInStatus isEqual: @"false"]){
NSLog(@"Wrong email/password combination!");
self.loginstat = @"false";
loggedInTF = false;
}
} failure:nil];
[operation start];
}
}
@end
我一直不明白 dispatch_sync 是如何运作的,
知道如何等待 [loginSingleton attemptToLogin];
完成吗?
attemptToLogin
大概是异步方法吧。您希望以这样的方式编写 attemptToLogin,以便在 HTTP 请求完成执行时为您提供回调。您可以通过完成块、委托或通知来做到这一点。
如果您等待请求完成,您将最终阻塞主线程,这将冻结用户交互,导致糟糕的用户体验。
- (void)attemptToLogin:(void(^)(BOOL login))complete {
...
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
....
// After you get login status
complete(your_login_status_here);
}
}
并且在CustomTabBarController
-(void)viewDidAppear:(BOOL)animated{
myCustomQueue = dispatch_queue_create("com.myDomain.appName", NULL);
loginSingleton = [LoginCheckSingleton sharedInstance];
[loginSingleton attemptToLogin:^(loginStatus){
if([loginStatus isEqual: @"true"]){
NSLog(@"Logged In");
}else{
NSLog(@"Not Logged In");
dispatch_async(dispatch_get_main_queue(), {
[self performSegueWithIdentifier:@"goToLoginView" sender:self];
});
}
}];
}