AFnetworking 2.0 ResponseObject处理
-
20-12-2019 - |
题
我有一个问题。也许是2个问题。
首先涉及这段代码:
-(void)isLoggedIn {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
.
我希望这个方法不是void,我希望它返回一个bool或我可以使用的东西:用户登录>确定在应用程序中的某个地方做某事;用户未登录>确定提示用户到屏幕,他可以介绍他的凭据并登录。
第二个问题与这段代码有关:
-(void)detail {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUser];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
.
我希望这个方法用解析的json返回一个nsarray,我可以在任何我想要的地方使用。
该方法包含在一个名为NetworkModel的模型中(NSObject子类)。我只是想知道为什么我应该在街区内做所有事情。我应该有碎片与网络交互,而不是在一个独特的地方/类中组织。有没有办法做到这一点。我不希望每个ViewController都有5行请求。我想定义我可以从任何ViewController调用的方法(显然导入需要的标题文件)。
任何建议? 谢谢你的建议!
解决方案
您可以用2个方法执行此操作,一个更改您的方法才能使用块或使用信号量等待异步请求:
信号量(丑陋的方式)
-(BOOL)isLoggedIn {
__block BOOL isLoggedIn;
dispatch_semaphore_t waiter = dispatch_semaphore_create(0);
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
isLoggedIn = YES;
dispatch_semaphore_signal(waiter);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
isLoggedIn = NO;
dispatch_semaphore_signal(waiter);
}];
dispatch_group_wait(waiter, DISPATCH_TIME_FOREVER);
return isLoggedIn;
}
.
正确的方法
-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
completionBlock(YES);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
completionBlock(NO);
}];
}
.
对于第二个问题,您可以在网络类上设置一个块变量,在请求完成或失败时将调用。
无论如何,我认为你不太熟悉块(因为你的第二个问题),我认为在几个街区之后你会开始喜欢它们,如果你有小片段代码,你会看到代码并不复杂执行请求和解析,您也将看到它易于调试它们并找到问题,我的意思是,这也是我的情况我开始使用块。
使用块变量
@interface YourNetworkClass:NSObject {
void(^resultHandlerBlock)(NSArray *results); //this block has as param a NSArray, you can change it to whatever you want
}
-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock;
@implementation YourNetworkClass
-(void)setResultHandlerBlock:(void(^)(NSArray *array))handlerBlock {
resultHandlerBlock = block;
}
-(void)anotherMethodThatDoesNetworkOperationsAndReturnsAnArray {
....
resultHandlerBlock(arrayOfResults);
}
@interface AViewControllerThatUseNetwork: UIViewController {
}
@implementation AViewControllerThatUseNetwork
-(void)initNetworkClass {
YourNetworkClass *networkClass = [[YourNetworkClass alloc] init]; //or other init methods
[networkClass setResultHandlerBlock:^(NSArray *results) {
//do whatever you want with the array
}];
}
. 其他提示
我问了一些类似的东西。我相信你会在那里找到你的解决方案。 传递块到afnetworking方法?
一般来说,您需要更改您认为从“如果登录返回bool”的方式更改以“检查我可以登录,如果失败在afnetworking块中做某事。上面的链接也回答了第二个问题。
您的方法应该采用将从AFnetworking成功(或失败)块执行的块(或两个)。这种方法拥有你想要做的事情的异步性质。由于此Asynchronicity,您无法为方法添加返回值。
所以,您会将方法更改为:
-(void)isLoggedInWithCompletion:(LoginCompletionBlock)completion {
...
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
completion(/* whatever parameters your block specifies */);
} ...
}
. 所以,对情况的更新很少(谢谢所有珍贵的建议..谢谢家伙!)。现在我的代码看起来像这样(在我的NetworkModel.m中,显然我已经将方法添加到NetworkModel.h,以便我可以在任何地方调用它):
-(void)isLoggedIn:(void(^)(BOOL isLoggedIn))completionBlock {
NSString *urlString = [NSString stringWithFormat:@"%@%@%@", kBaseURL, kAPI, kUserIsLogged];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
if ([[NSString stringWithFormat:@"%@", responseObject] isEqualToString:@"true"]) {
completionBlock(YES);
} else {
completionBlock(NO);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
completionBlock(NO);
}];
}
.
在我的appdelegate.h中我包含我的networkmodel.h和我的appdelegate.m我现在有以下代码:
[[self model] isLoggedIn:^(BOOL isLoggedIn) {
if (isLoggedIn == YES) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start01"];
[self.window setRootViewController:controller];
} else {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:@"Start00"];
[self.window setRootViewController:controller];
}
}];
.
,它有点好。但现在我对此有另一个问题。当我运行应用程序时,发生了一些奇怪的事情。一旦它检索有关用户登录状态的信息,它将从VC(帐单板上的指定初始步骤控制器 - Start00)跳转到VC(在我的故事板上的LoggedInvc - Start01)。有没有办法没有向用户跳起来的方式?或者这是一个正常行为?现在用户看到了第二个屏幕,然后他应该实际看到的屏幕(因为他登录)。
但我想使用块的最简单方法以及所有这些方法是在我需要它们的地方使用它们。而不是尝试将它们封装成方法或类或其他任何东西。一旦数据在那里,我就会做我的拥有,直接在成功或失败块内。我觉得对吗?