我有一个问题。也许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);
}];
}
我希望这个方法不是一个空白,我希望它返回一个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调用的方法(显然在需要的地方导入头文件)。
有什么建议吗? 谢谢你的建议!
答案 0 :(得分:3)
您可以使用两种方法执行此操作,一种更改方法以使用块或使用信号量等待异步请求:
使用信号量(THE UGLY WAY)
-(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
}];
}
答案 1 :(得分:1)
您的方法应采用将从AFNetworking成功(或失败)块执行的块(或两个)。这种方法包含了您尝试做的异步性质。由于这种异步性,您无法向方法添加返回值。
因此,您可以将方法更改为:
-(void)isLoggedInWithCompletion:(LoginCompletionBlock)completion {
...
[manager GET:urlString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
completion(/* whatever parameters your block specifies */);
} ...
}
答案 2 :(得分:1)
一般情况下,您需要更改您认为应该从&#34获取数据的方式;如果登录返回BOOL" to"检查我是否可以登录,如果失败则在AFNetworking块中执行某些操作。
上面的链接也回答了你的第二个问题。
答案 3 :(得分:0)
所以,对情况的更新很少(感谢所有宝贵的建议......谢谢你们!)。现在我的代码看起来像这样(在我的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(指定的InitialView Controller - 我的故事板上的Start00)跳转到VC(在我的故事板上的loggedInVC - Start01)。有没有办法不向用户展示这种跳跃?或者这是正常的行为?现在,用户会看到第一个屏幕,然后是他应该看到的屏幕(因为他已登录)。
但我想使用块的最简单方法就是在我需要的地方使用它们。而不是试图将它们封装到方法或类或其他任何东西中。一旦数据存在,我就会直接在成功或失败区域内做我所拥有的。我在想什么?