2013-11-15 90 views
3

我有一个问题。也许2个问题。AFNetworking 2.0 responseObject处理

首先一个涉及这段代码:

-(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或东西,我可以使用像:用户是登录>确定在应用程序中的某处执行某些操作;用户未登录> OK提示用户在屏幕上,在那里他可以介绍他的凭据,并登录

第二个问题是有关这段代码:

-(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调用的方法(显然在需要的地方导入头文件)。

有什么建议吗? 谢谢您的建议!

回答

3

你可以用2名的方法做到这一点,一个改变以使用块或使用信号量等待异步请求的方法:

随着信号量(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 
}]; 
} 
+0

我会检查一下。关于我对块的熟悉程度,你是完全正确的。此外,当我需要它时,我已经习惯了数据,而这种异步的东西现在正在混淆我的头......但我会习惯它。我只需要首先理解:这就是为什么我问了一个虚拟问题。 – user1447316

+0

因此,关于第二个问题,您建议我创建一个块变量,然后在成功块中设置:blockVariable = responceObject? – user1447316

+1

@ user1447316检查我编辑的答案 – danypata

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 */); 
    } ... 
} 
+0

我意识到这种异步性,这就是为什么我要求最好的方式来做到这一点,尊重这一事实。你能告诉我一个我用代码问的例子吗?谢谢你的建议。 – user1447316

1

我问类似的东西而回。我相信你会在那里找到你的解决方案。 Passing blocks to a AFNetworking method?

一般情况下,你需要改变你的思考,你应该从获取数据的方式“如果登录回报BOOL”,以“检查,如果我可以登录,如果失败的AFNetworking块内做一些事情。

上面还链接回答你的第二个问题

+0

有趣的建议!谢谢!嗯..我的问题是,如果我“检查,如果我可以登录”,我的服务器将根据我是否真的登录或不真实回答成功块中的TRUE或FALSE。我应该如何处理?如果用户是IN或OUT,它将会成功。只有在服务器出于某种原因而关闭的情况下才会失败,或者我查询了无效的链接或其他内容。 – user1447316

+1

如果登录成功或不成功,您需要向用户发送一个请求,登录密码并在成功块内获得响应。例如,发送[email protected] 123到服务器,服务器将返回:嗨!我知道那家伙!你将进入成功模块。然后你可以移动到Logged In ViewController。 – Segev

+0

谢谢!这正是我所做的。我发布了一个我的问题的答案。 – user1447316

0

因此,在不大的情况下更新(所有珍贵suggestions..thanks家伙谢谢!)。现在,我的代码看起来像这样(在我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控制器 - Storyboard上的Start00)跳转到VC(loggedInVC - Storyboard上的Start01)。有没有办法不向用户展示这种有点跳跃?或者这是一个正常的行为?现在用户会看到第一个屏幕,然后是他应该看到的屏幕(因为他已登录)。

但我想最简单的方法来处理块,所有这一切都是在我需要它们的地方使用它们。而不是试图将它们封装到方法或类或其他类中。只要数据在那里,我就会直接在成功或失败块中做我所拥有的。我在想对吗?