Can AFNetworking return data synchronously (inside a block)?
To block the execution of the main thread until the operation completes, you could do [operation waitUntilFinished]
after it's added to the operation queue. In this case, you wouldn't need the return
in the block; setting the __block
variable would be enough.
That said, I'd strongly discourage forcing asynchronous operations to synchronous methods. It's tricky to get your head around sometimes, but if there's any way you could structure this to be asynchronous, that would almost certainly be the way to go.
How to use AFNetworking 2.0 synchronously
You should not make an inherently asynchronous method synchronous, but instead make your call-site asynchronous as well.
That is, your method becomes asynchronous and provides a completion handler:
- (void) userWithUsername:(NSString *)username
password:(NSString *)password
completion:(completion_handler_t)completion;
where completion_handler_t
is a type definition and may be declared in the header file like this:
typedef void (^completion_handler_t)(User*, NSError*);
Note that using a typedef
is optional and may make your code more comprehensible.
Then you can use it as follows:
[self userWithUsername:username
password:password
completion:^(User* user, NSError*error){
// Check error; do something with user
...
}];
You can implement it as shown below:
- (void) userWithUsername:(NSString *)username
password:(NSString *)password
completion:(completion_handler_t)completion
{
NSDictionary *params = @{@"email": username, @"password": password};
[[DCAPIClient sharedClient] POST:@"login" parameters:params
success:^(NSURLSessionDataTask * __unused task, id JSONResult) {
NSLog(@"JSON %@", JSONResult);
BOOL errorCode = [JSONResult objectForKey:@"error"];
if (!errorCode) {
self.username = [JSONResult objectForKey:@"name"];
// Fill the attributes
// self.email = .. a
if (completion) {
completion(theUser, nil); // completion(self, nil)??
}
} else {
if (completion) {
completion(nil, error);
}
}
} failure:^(NSURLSessionDataTask *__unused task, NSError *error) {
if (completion) {
completion(nil, error);
}
}];
}
AFNetworking to run synchronously
I want to run it synchronously to do a package download (I need to get the list of services that people will be able to choose from). How can I do this?
AFNetworking does not support sync operations.
On the other hand, you almost never want sync operations on your UI thread, because the UI would become unresponsive.
(I need to get the list of services that people will be able to choose from)
What you could do is displaying some UI hint that the list of services is being downloaded while the async operation is in progress.
Wait for AFNetworking completion block before continuing (i.e. Synchronous)
It sounds like there's a part of your app that can't run until a starting request is done. But there's also a part that can run (like the part that starts the request). Give that part a UI that tells the user that we're busy getting ready. No blocking the UI.
But if you must, and if AFNetworking doesn't provide a blocking version of a request (kudos to them for that), then you could always block the old fashioned way...
- (void)pleaseDontUseThisIdea {
__block BOOL thePopeIsCatholic = YES;
[manager GET: ....^{
// ...
thePopeIsCatholic = NO;
}];
while (thePopeIsCatholic) {}
}
Return data after AFNetworking is done
I don't think you know how Asynchronous operations work. The NSMutableArray
will never be set, because it is returned synchronously.
In your case, I suggest you to work with delegates.
- (void)getTournamentsInClub:(NSString *)clubGUID withDelegateViewController:(UIViewController *)viewController completionBlock:(void (^)(NSMutableArray *result))completionBlock {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSMutableArray *responseArray = [[[NSMutableArray alloc] init] autorelease];
NSString *URL = [[NSString alloc]initWithFormat:@"SomeURL=%@",clubGUID];
[manager POST:URL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
for (id obj in responseObject) {
[responseArray addObject:obj];
}
// Request finished. Call the block.
completionBlock(responseArray);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];
}
- (void)handleClubTournaments {
GP_MobilAppDelegate *xdelegate = [[UIApplication sharedApplication] delegate];
[[TournamentsWebService sharedToursWS] getTournamentsInClub:^(NSMutableArray *result)
{
// Hide the Loading Indicator. Do something with the Result.
}];
// You can't access the result synchronously, therefore it's impossible to depend on it synchronously.
}
another way to return the data asynchronously would be blocks, similar to the AFNetworking
solution.
You can read more about getting started with blocks here and how to use delegates here.
Related Topics
Is There a Good Charting Library For Iphone
The Model Used to Open the Store Is Incompatible With the One Used to Create the Store
Remove or Uninstall Library Previously Added: Cocoapods
How to Crop a Uiimageview to a New Uiimage in 'Aspect Fill' Mode
Navigation Controller Push View Controller
Xcode 6 - Xcassets For Universal Image Support
Why Is Wkwebview Not Opening Links With Target="_Blank"
Auto Layout Constraints Issue on iOS7 in Uitableviewcell
Issue Using Cccrypt (Commoncrypt) in Swift
Uicollectionview Flowlayout Not Wrapping Cells Correctly
How to Simultaneously Satisfy Constraints, Will Attempt to Recover by Breaking Constraint
Programmatically Align a Toolbar on Top of the Iphone Keyboard
What Are Sprite Kit'S "Category Mask" and "Collision Mask"
Command Failed Due to Signal: Segmentation Fault: 11
How to Change Multiplier Property For Nslayoutconstraint