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
Sync Video in Avplayerlayer and Avplayerviewcontroller
Strange Custom Background Color on Uipickerview Swift
CSS Flexible Box Layout on Ipad
Using Shader Modifiers to Animate Texture in Scenekit Leads to Jittery Textures Over Time
Core Data - Fetch All Entities Using the Same Field
Cannot Subscript a Value of [Anyobject]? with an Index of Type Int
Swiftui: Navigate to Home Screen After Login Completed. Navigating Views by Button Click
Passing Arguments to @Selector Method
Updating Sqlite Database Without Xml
Googlemap API Gives Wrong Coordinates for Direction Between Two Points
Pass Extra Argument for UItapgesturerecognizer with Selector
How to Get the Index in Results of a Certain Realm Object
Reusing View in UIpickerview with iOS 7
Ionic 3 Response with Status: 0 for Url: Null
How to Queue Multiple Accessibility Notifications for Voiceover
Calculate The Range of Visible Text in UIlabel