Multiple Async Requests at Once in Objective C

Multiple async requests at once in objective c

You can use "AsyncImageView" class files it will load image synchronously and it shows the activity indicator while image loading

AsyncImageView is the class file in which it will create connection for each call and when image data downloading completed it will return image for imageview. and if image is already in cache then just return image without creating connection.

You can download "AsyncImageView" class files from following link:- https://www.dropbox.com/s/peazwjvky9fsjd7/Archive.zip

in .m file import AsyncImageView Class

  #import "AsyncImageView.h" 

in your tableview cell at indexpath method

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"SimpleTableCell";
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(X, y, width, height)];

NSString *imageURL = [NSString stringWithFormat: @"www.xyz.image.png"];
AsyncImageView *async = [[AsyncImageView alloc]initWithFrame:CGRectMake(0, 0, width, height)];
[async loadImageFromURL:[NSURL URLWithString:imageURL]];
[imageView addSubview:async];
[cell addSubview:imageView];
return cell;
}

try this your problem will solve.

Manage multiple asynchronous operation on XCTests

Use

dispatch_group

To create a chain of events.

At the start of your test:

Dispatch_group_t group = dispatch_group_create();

Before each async portion call:

Dispatch_group_enter(group);

And when each async portion has finished use:

Dispatch_group_leave(group);

(The number of "enter" must equal the number of "leave")

At the end of the async code "wait" :

// called when "group" |enter|=|leave|
Dispatch_group_apply(group,main_queue,^{

// check your conditions....
If (success) [expectation fulfill];
Else // failure
});

Expectation wait....// add the expectation wait handler as before

There are different variations of dispatch_group so you may need to tweak according to your use case.

Hope it helps

*******EDIT*******

Per your comment, you may want to nest the groups differently. For instance:

// create the expectation
Expectation = ....

dispatch_group_t myGroup = dispatch_group_create();

dispatch_group_enter(myGroup);
// do first portion
dispatch_group_leave(myGroup);

// do the second portion after the first
dispatch_group_apply(myGroup,dispatch_queue..., ^{
//second code portion

// chain as many as needed using this technique

// eventually you will need to fulfill your "expectation
// ...
if (success) {
[expectation fullfil];
} else {
XCTAssert(fail,@"The test failed because ....");
}
});

[self expectation wait...]

Managing multiple asynchronous NSURLConnection connections

I track responses in an CFMutableDictionaryRef keyed by the NSURLConnection associated with it. i.e.:

connectionToInfoMapping =
CFDictionaryCreateMutable(
kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);

It may seem odd to use this instead of NSMutableDictionary but I do it because this CFDictionary only retains its keys (the NSURLConnection) whereas NSDictionary copies its keys (and NSURLConnection doesn't support copying).

Once that's done:

CFDictionaryAddValue(
connectionToInfoMapping,
connection,
[NSMutableDictionary
dictionaryWithObject:[NSMutableData data]
forKey:@"receivedData"]);

and now I have an "info" dictionary of data for each connection that I can use to track information about the connection and the "info" dictionary already contains a mutable data object that I can use to store the reply data as it comes in.

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSMutableDictionary *connectionInfo =
CFDictionaryGetValue(connectionToInfoMapping, connection);
[[connectionInfo objectForKey:@"receivedData"] appendData:data];
}

Wait until multiple networking requests have all executed - including their completion blocks

Use dispatch groups.

dispatch_group_t group = dispatch_group_create();

MyCoreDataObject *coreDataObject;

dispatch_group_enter(group);
AFHTTPRequestOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation1 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
coreDataObject.attribute1 = responseObject;
sleep(5);
dispatch_group_leave(group);
}];
[operation1 start];

dispatch_group_enter(group);
AFHTTPRequestOperation *operation2 = [[AFHTTPRequestOperation alloc] initWithRequest:request1];
[operation2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
coreDataObject.attribute2 = responseObject;
sleep(10);
dispatch_group_leave(group);
}];
[operation2 start];

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);

[context save:nil];

Objective-C – Waiting for two async methods to complete

Assuming you actually have some sort of way of knowing when the asynchronous methods are done, what you probably want is something like:

- (void)syncData {

// Show activity indicator
[object sync]; // Synchronous method
[object2 sync]; // Synchronous method

_object3Synced = _object4Synced = NO;
[object3 syncWithCompletionHandler:
^{
_object3Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
[object4 syncWithCompletionHandler:
^{
_object4Synced = YES;
[self considerHidingActivityIndicator];
}]; // Async method
}

- (void)considerHidingActivityIndicator
{
if(_object3Synced && _object4Synced)
{
// hide activity indicator, etc
}
}

Multiple i/o with an mutable object from different async requests

There is always a risk when two threads can mutate data at the same time. For the most simple case you can use synchronization like this:

@synchronized (self) {
[someMutabelArray addObject:someObject];
}

For more complex situation where someMutabelArray can be modified from many different methods you will need to use a NSLock or one of the other classes conforming to the NSLocking protocol that best suits your needs.

How to perform multiple asynchronous requests starting one after another

You are on the right track with the DispatchSemaphore to ensure that an asyncronous call is not started before the previous one has finished. I would just ensure that the code that manages the calls to the asyncronous API runs in the background:

let backgroundQueue = DispatchQueue(label: "requests")
let semaphore = DispatchSemaphore(value: 1)

backgroundQueue.async {
var requestNumber = 1

for request in requests {
semaphore.wait()

let currentRequestNumber = requestNumber

print("Request launched #\(requestNumber)")

apiManager().performAsyncRequest(request,
failure: {
error in
print("Request error #\(currentRequestNumber)")
semaphore.signal()
}) {
print("Request result #\(currentRequestNumber)")
semaphore.signal()
}

requestNumber = requestNumber + 1
}
}

The code will continue execution immediatelly while the for loop runs in a background loop and starts each request after waiting for the previous one to finish.

Or if apiManager() is not thread safe:

let semaphore = DispatchSemaphore(value: 1)

var requestNumber = 1

for request in requests {
semaphore.wait()

let currentRequestNumber = requestNumber

print("Request launched #\(requestNumber)")

apiManager().performAsyncRequest(request,
failure: {
error in
print("Request error #\(currentRequestNumber)")
semaphore.signal()
}) {
print("Request result #\(currentRequestNumber)")
semaphore.signal()
}

requestNumber = requestNumber + 1
}

This has the limitation that the for loop will be in execution until the last request starts execution. But if the code you are calling is not thread safe there is no way around that.

Executing Multiple Async Request Simultaneously

I would personally go about it using NSOperation. It doesn't take much time to implement and if this is really the only networking you will be doing AFNetworking maybe overkill.

That being said, if you are not comfortable with NSOperation or NSURLConnection, then AFNetworking might be the way to go.

In my opinion:

NSOperation = super light weight and performs your task to the "T".

AFNetworking = what you need plus 100 other things you don't need.


Per comment:

An example of executing 3 request without dependency among each other could be done with NSOperation like this (pseudo):

NSOperationQueue *myQueue....create NSOperationQueue

FetchProfilePictureOperation *fetchPictureOperation.....Sublcass of NSOperation
fetchPictureOperation.completionBlock = ^{
dispatch_async(dispatch_get_main_queue(),^{
NSLog("fetchPictureOperation Completed");
});
};

FetchProfileIconOperation *fetchIconOperation....Subclass of NSOperation
fetchIconOperation.completionBlock = ^{
dispatch_async(dispatch_get_main_queue(),^{
NSLog("fetchIconOperation Completed");
});
};

FetchProfileDetailsOperation *fetchDetailsOperation....Subclass of NSOperation
fetchDetailsOperation.completionBlock = ^{
dispatch_async(dispatch_get_main_queue(),^{
NSLog("fetchDetailsOperation Completed");
});
};

[myQueue addOperation: fetchPictureOperation];
[myQueue addOperation: fetchIconOperation];
[myQueue addOperation: fetchDetailsOperation];

Here is a reference to NSOperation from the guy who wrote AFNetworking that is helpful.



Related Topics



Leave a reply



Submit