I have internet connection and can browsing with browser.
Here is my codes to check Reachability with AFNetworking.
- (BOOL)connected {
return [AFNetworkReachabilityManager sharedManager].reachable;
}
And In ViewDidLoad
BOOL isOnline = [self connected];
if(isOnline == YES)
{
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
It's only showing NO and i don't know why is it?
Is there easiest way to check Reachability with AFNetworking?
I guess startMonitoring isn't called, try to do the below:
- (void)viewDidLoad {
[super viewDidLoad];
....
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
}
If above answer is not solving your issue,
then your problem might be due to calling [AFNetworkReachabilityManager sharedManager].reachable while it is in the middle of 'startMonitoring' process where it would always return NO.
I had the same issue. I was calling web service while AFNetworkReachabilityManager had not finished monitoring process and was returning reachable = NO although I had working internet connection.
- (void) callWebService {
NSLog(#"Calling Webservice...");
if ([AFNetworkReachabilityManager sharedManager].reachable == NO) {
NSLog(#"%#", kErrorNoInternet);
return;
}
// Now, proceed to call webservice....
}
So, to solve this I did a trick. Called web service after some delay (in this example 0.05 sec).
Before:
[self callWebService];
Output:
After:
[self performSelector:#selector(callWebService) withObject:nil afterDelay:0.3]; // you can set delay value as per your choice
Output:
You can see from the output, the time difference is hardly 0.05 sec (exact value 0.048 sec).
Hope this will help.
instead of waiting you can use blocks just to make sure that your web service will be only called when network is available.
[[AFNetworkReachabilityManager sharedManager]startMonitoring];
[[AFNetworkReachabilityManager sharedManager]setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status)
{
if (status == AFNetworkReachabilityStatusReachableViaWWAN || status == AFNetworkReachabilityStatusReachableViaWiFi)
{
// connected. you can call your web service here
}else
{
// internet disconnected
}
}];
I have been trying to use dispatch_async in a method that returns a result. However, I observed that the method returns before executing the dispatch_async block. Due to this I'm not getting the results I expect. Here is some code that demonstrates my problem.
-(BOOL) isContactExists {
BOOL isContactExistsInXYZ = YES;
UserId *userId = contact.userId;
dispatch_async(dispatch_get_main_queue(), ^
{
iOSContact *contact = [iOSContact contactForUserId:userId];
if (nil == contact)
{
isContactExistsInXYZ = NO;
}
});
return isContactExistsInXYZ;
}
This method isContactExists is called somewhere else and based on the response from that method I have to do some stuff. But every time, the value of isContactExistsInXYZ is not what I expect. How do I handle dispatch_async in this situation?
If your going the block route your method needs to look something like this.
- (void)isContactExistsWithCompletionHandler:(void(^)(BOOL exists)) completion
{
dispatch_async(dispatch_get_main_queue(), ^
{
BOOL isContactExistsInXYZ = YES;
UserId *userId = contact.userId;
iOSContact *contact = [iOSContact contactForUserId:userId];
if (nil == contact)
{
isContactExistsInXYZ = NO;
}
completion(isContactExistsInXYZ);
});
}
And where you are calling it something like this.
[someObject isContactExistsWithCompletionHandler:^(BOOL exists) {
// do something with your BOOL
}];
You should also consider placing your heavy operations in a other que than main. Like this.
- (void)isContactExistsWithCompletionHandler:(void(^)(BOOL exists)) completion
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
dispatch_async(queue, ^
{
BOOL isContactExistsInXYZ = YES;
UserId *userId = contact.userId;
iOSContact *contact = [iOSContact contactForUserId:userId];
if (nil == contact)
{
isContactExistsInXYZ = NO;
}
dispatch_async(dispatch_get_main_queue(), ^
{
completion(isContactExistsInXYZ);
});
});
}
You need to respect that what you are trying to do is asynchronous and embrace that. This means not using a return value. Instead you can write your method to take a callback block as a parameter. Then, when your asynchronous check is complete you can call the block with the result.
So your method signature would become:
- (void)checkIfContactExistsWithCompletion:(ContactExistsBlock)completion {
Where ContactExistsBlock is a block definition with no return and probably a single BOOL parameter.
typedef void (^ContactExistsBlock) (BOOL exists);
The reason is dispatch_async(dispatch_get_main_queue(), ^does not wait until execution is done. You are probably messing up stuff there. Normally, this is used to update UI asynchronously along with other server content getting downloaded in some other thread. Try using dispatch_sync instead.
When using methods which return blocks they can be very convenient.
However, when you have to string a few of them together it gets messy really quickly
for instance, you have to call 4 URLs in succession:
[remoteAPIWithURL:url1 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
[remoteAPIWithURL:url3 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
//succes!!!
}];
}];
}];
}];
So for every iteration I go one level deeper, and I don't even handle errors in the nested blocks yet.
It gets worse when there is an actual loop. For instance, say I want to upload a file in 100 chunks:
- (void) continueUploadWithBlockNr:(int)blockNr
{
if(blocknr>=100)
{
//success!!!
}
[remoteAPIUploadFile:file withBlockNr:blockNr success:^(int status)
{
[self continueUploadWithBlockNr:blockNr];
}];
}
This feels very unintuitive, and gets very unreadable very quick.
In .Net they solved all this using the async and await keyword, basically unrolling these continuations into a seemingly synchronous flow.
What is the best practice in Objective C?
Your question immediately made me think of recursion. Turns out, Objective-c blocks can be used in recursion. So I came up with the following solution, which is easy to understand and can scale to N tasks pretty nicely.
// __block declaration of the block makes it possible to call the block from within itself
__block void (^urlFetchBlock)();
// Neatly aggregate all the urls you wish to fetch
NSArray *urlArray = #[
[NSURL URLWithString:#"http://www.google.com"],
[NSURL URLWithString:#"http://www.stackoverflow.com"],
[NSURL URLWithString:#"http://www.bing.com"],
[NSURL URLWithString:#"http://www.apple.com"]
];
__block int urlIndex = 0;
// the 'recursive' block
urlFetchBlock = [^void () {
if (urlIndex < (int)[urlArray count]){
[self remoteAPIWithURL:[urlArray objectAtIndex:index]
success:^(int theStatus){
urlIndex++;
urlFetchBlock();
}
failure:^(){
// handle error.
}];
}
} copy];
// initiate the url requests
urlFetchBlock();
One way to reduce nesting is to define methods that return the individual blocks. In order to facilitate the data sharing which is done "auto-magically" by the Objective C compiler through closures, you would need to define a separate class to hold the shared state.
Here is a rough sketch of how this can be done:
typedef void (^WithStatus)(int);
#interface AsyncHandler : NSObject {
NSString *_sharedString;
NSURL *_innerUrl;
NSURL *_middleUrl;
WithStatus _innermostBlock;
}
+(void)handleRequest:(WithStatus)innermostBlock
outerUrl:(NSURL*)outerUrl
middleUrl:(NSURL*)middleUrl
innerUrl:(NSURL*)innerUrl;
-(WithStatus)outerBlock;
-(WithStatus)middleBlock;
#end
#implementation AsyncHandler
+(void)handleRequest:(WithStatus)innermostBlock
outerUrl:(NSURL*)outerUrl
middleUrl:(NSURL*)middleUrl
innerUrl:(NSURL*)innerUrl {
AsyncHandler *h = [[AsyncHandler alloc] init];
h->_innermostBlock = innermostBlock;
h->_innerUrl = innerUrl;
h->_middleUrl = middleUrl;
[remoteAPIWithURL:outerUrl success:[self outerBlock]];
}
-(WithStatus)outerBlock {
return ^(int success) {
_sharedString = [NSString stringWithFormat:#"Outer: %i", success];
[remoteAPIWithURL:_middleUrl success:[self middleBlock]];
};
}
-(WithStatus)middleBlock {
return ^(int success) {
NSLog("Shared string: %#", _sharedString);
[remoteAPIWithURL:_innerUrl success:_innermostBlock];
};
}
#end
Note: All of this assumes ARC; if you are compiling without it, you need to use Block_copy in the methods returning blocks. You would also need to do a copy in the calling code below.
Now your original function can be re-written without the "Russian doll" nesting, like this:
[AsyncHandler
handleRequest:^(int status){
//succes!!!
}
outerUrl:[NSURL #"http://my.first.url.com"]
middleUrl:[NSURL #"http://my.second.url.com"]
innerUrl:[NSURL #"http://my.third.url.com"]
];
Iterative algorithm:
Create a __block variable (int urlNum) to keep track of the current URL (inside an NSArray of them).
Have the onUrlComplete block fire off the next request until all URLs have been loaded.
Fire the first request.
When all URLs have been loaded, do the "//success!" dance.
Code written without the aid of XCode (meaning, there may be compiler errors -- will fix if necessary):
- (void)loadUrlsAsynchronouslyIterative:(NSArray *)urls {
__block int urlNum = 0;
void(^onUrlComplete)(int) = nil; //I don't remember if you can call a block from inside itself.
onUrlComplete = ^(int status) {
if (urlNum < urls.count) {
id nextUrl = urls[urlNum++];
[remoteAPIWithURL:nextUrl success:onUrlComplete];
} else {
//success!
}
}
onUrlComplete(0); //fire first request
}
Recursive algorithm:
Create a method to load all the remaining URLs.
When remaining URLs is empty, fire "onSuccess".
Otherwise, fire request for the next URL and provide a completion block that recursively calls the method with all but the first remaining URLs.
Complications: we declared the "onSuccess" block to accept an int status parameter, so we pass the last status variable down (including a "default" value).
Code written without the aid of XCode (bug disclaimer here):
- (void)loadUrlsAsynchronouslyRecursive:(NSArray *)remainingUrls onSuccess:(void(^)(int status))onSuccess lastStatus:(int)lastStatus {
if (remainingUrls.count == 0) {
onSuccess(lastStatus);
return;
}
id nextUrl = remainingUrls[0];
remainingUrls = [remainingUrls subarrayWithRange:NSMakeRange(1, remainingUrls.count-1)];
[remoteAPIWithUrl:nextUrl onSuccess:^(int status) {
[self loadUrlsAsynchronouslyRecursive:remainingUrls onSuccess:onSuccess lastStatus:status];
}];
}
//fire first request:
[self loadUrlsAsynchronouslyRecursive:urls onSuccess:^(int status) {
//success here!
} lastStatus:0];
Which is better?
The iterative algorithm is simple and concise -- if you're comfortable playing games with __block variables and scopes.
Alternatively, the recursive algorithm doesn't require __block variables and is fairly simple, as recursive algorithms go.
The recursive implementation is more re-usable that the iterative one (as implemented).
The recursive algorithm might leak (it requires a reference to self), but there are several ways to fix that: make it a function, use __weak id weakSelf = self;, etc.
How easy would it be to add error-handling?
The iterative implementation can easily be extended to check the value of status, at the cost of the onUrlComplete block becoming more complex.
The recursive implementation is perhaps not as straight-forward to extend -- primarily because it is re-usable. Do you want to cancel loading more URLs when the status is such-and-such? Then pass down a status-checking/error-handling block that accepts int status and returns BOOL (for example YES to continue, NO to cancel). Or perhaps modify onSuccess to accept both int status and NSArray *remainingUrls -- but you'll need to call loadUrlsAsynchronouslyRecursive... in your onSuccess block implementation.
You said (in a comment), “asynchronous methods offer easy asynchronisity without using explicit threads.” But your complaint seems to be that you're trying to do something with asynchronous methods, and it's not easy. Do you see the contradiction here?
When you use a callback-based design, you sacrifice the ability to express your control flow directly using the language's built-in structures.
So I suggest you stop using a callback-based design. Grand Central Dispatch (GCD) makes it easy (that word again!) to perform work “in the background”, and then call back to the main thread to update the user interface. So if you have a synchronous version of your API, just use it in a background queue:
- (void)interactWithRemoteAPI:(id<RemoteAPI>)remoteAPI {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// This block runs on a background queue, so it doesn't block the main thread.
// But it can't touch the user interface.
for (NSURL *url in #[url1, url2, url3, url4]) {
int status = [remoteAPI syncRequestWithURL:url];
if (status != 0) {
dispatch_async(dispatch_get_main_queue(), ^{
// This block runs on the main thread, so it can update the
// user interface.
[self remoteRequestFailedWithURL:url status:status];
});
return;
}
}
});
}
Since we're just using normal control flow, it's straightforward to do more complicated things. Say we need to issue two requests, then upload a file in chunks of at most 100k, then issue one more request:
#define AsyncToMain(Block) dispatch_async(dispatch_get_main_queue(), Block)
- (void)uploadFile:(NSFileHandle *)fileHandle withRemoteAPI:(id<RemoteAPI>)remoteAPI {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
int status = [remoteAPI syncRequestWithURL:url1];
if (status != 0) {
AsyncToMain(^{ [self remoteRequestFailedWithURL:url1 status:status]; });
return;
}
status = [remoteAPI syncRequestWithURL:url2];
if (status != 0) {
AsyncToMain(^{ [self remoteRequestFailedWithURL:url2 status:status]; });
return;
}
while (1) {
// Manage an autorelease pool to avoid accumulating all of the
// 100k chunks in memory simultaneously.
#autoreleasepool {
NSData *chunk = [fileHandle readDataOfLength:100 * 1024];
if (chunk.length == 0)
break;
status = [remoteAPI syncUploadChunk:chunk];
if (status != 0) {
AsyncToMain(^{ [self sendChunkFailedWithStatus:status]; });
return;
}
}
}
status = [remoteAPI syncRequestWithURL:url4];
if (status != 0) {
AsyncToMain(^{ [self remoteRequestFailedWithURL:url4 status:status]; });
return;
}
AsyncToMain(^{ [self uploadFileSucceeded]; });
});
}
Now I'm sure you're saying “Oh yeah, that looks great.” ;^) But you might also be saying “What if RemoteAPI only has asynchronous methods, not synchronous methods?”
We can use GCD to create a synchronous wrapper for an asynchronous method. We need to make the wrapper call the async method, then block until the async method calls the callback. The tricky bit is that perhaps we don't know which queue the async method uses to invoke the callback, and we don't know if it uses dispatch_sync to call the callback. So let's be safe by calling the async method from a concurrent queue.
- (int)syncRequestWithRemoteAPI:(id<RemoteAPI>)remoteAPI url:(NSURL *)url {
__block int outerStatus;
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
[remoteAPI asyncRequestWithURL:url completion:^(int status) {
outerStatus = status;
dispatch_semaphore_signal(sem);
}];
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_release(sem);
return outerStatus;
}
UPDATE
I will respond to your third comment first, and your second comment second.
Third Comment
Your third comment:
Last but not least, your solution of dedicating a separate thread to wrap around the synchronous version of a call is more costly than using the async alternatives. a Thread is an expensive resource, and when it is blocking you basically have lost one thread. Async calls (the ones in the OS libraries at least) are typically handled in a much more efficient way. (For instance, if you would request 10 urls at the same time, chances are it will not spin up 10 threads (or put them in a threadpool))
Yes, using a thread is more expensive than just using the asynchronous call. So what? The question is whether it's too expensive. Objective-C messages are too expensive in some scenarios on current iOS hardware (the inner loops of a real-time face detection or speech recognition algorithm, for example), but I have no qualms about using them most of the time.
Whether a thread is “an expensive resource” really depends on the context. Let's consider your example: “For instance, if you would request 10 urls at the same time, chances are it will not spin up 10 threads (or put them in a threadpool)”. Let's find out.
NSURL *url = [NSURL URLWithString:#"http://1.1.1.1/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
for (int i = 0; i < 10; ++i) {
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(#"response=%# error=%#", response, error);
}];
}
So here I am using Apple's own recommended +[NSURLConnection sendAsynchronousRequest:queue:completionHandler:] method to send 10 requests asynchronously. I've chosen the URL to be non-responsive, so I can see exactly what kind of thread/queue strategy Apple uses to implement this method. I ran the app on my iPhone 4S running iOS 6.0.1, paused in the debugger, and took a screen shot of the Thread Navigator:
You can see that there are 10 threads labeled com.apple.root.default-priority. I've opened three of them so you can see that they are just normal GCD queue threads. Each calls a block defined in +[NSURLConnection sendAsynchronousRequest:…], which just turns around and calls +[NSURLConnection sendSynchronousRequest:…]. I checked all 10, and they all have the same stack trace. So, in fact, the OS library does spin up 10 threads.
I bumped the loop count from 10 to 100 and found that GCD caps the number of com.apple.root.default-priority threads at 64. So my guess is the other 36 requests I issued are queued up in the global default-priority queue, and won't even start executing until some of the 64 “running” requests finish.
So, is it too expensive to use a thread to turn an asynchronous function into a synchronous function? I'd say it depends on how many of these you plan to do simultaneously. I would have no qualms if the number's under 10, or even 20.
Second Comment
Which brings me to your second comment:
However, when you have: do these 3 things at the same time, and when 'any' of them is finished then ignore the rest and do these 3 calls at the same time and when 'all' of them finish then succes.
These are cases where it's easy to use GCD, but we can certainly combine the GCD and async approaches to use fewer threads if you want, while still using the languages native tools for control flow.
First, we'll make a typedef for the remote API completion block, just to save typing later:
typedef void (^RemoteAPICompletionBlock)(int status);
I'll start the control flow the same way as before, by moving it off the main thread to a concurrent queue:
- (void)complexFlowWithRemoteAPI:(id<RemoteAPI>)remoteAPI {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
First we want to issue three requests simultaneously and wait for one of them to succeed (or, presumably, for all three to fail).
So let's say we have a function, statusOfFirstRequestToSucceed, that issues any number of asynchronous remote API requests and waits for the first to succeed. This function will provide the completion block for each async request. But the different requests might take different arguments… how can we pass the API requests to the function?
We can do it by passing a literal block for each API request. Each literal block takes the completion block and issues the asynchronous remote API request:
int status = statusOfFirstRequestToSucceed(#[
^(RemoteAPICompletionBlock completion) {
[remoteAPI requestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI anotherRequestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI thirdRequestWithCompletion:completion];
}
]);
if (status != 0) {
AsyncToMain(^{ [self complexFlowFailedOnFirstRoundWithStatus:status]; });
return;
}
OK, now we've issued the three first parallel requests and waited for one to succeed, or for all of them to fail. Now we want to issue three more parallel requests and wait for all to succeed, or for one of them to fail. So it's almost identical, except I'm going to assume a function statusOfFirstRequestToFail:
status = statusOfFirstRequestToFail(#[
^(RemoteAPICompletionBlock completion) {
[remoteAPI requestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI anotherRequestWithCompletion:completion];
},
^(RemoteAPICompletionBlock completion) {
[remoteAPI thirdRequestWithCompletion:completion];
}
]);
if (status != 0) {
AsyncToMain(^{ [self complexFlowFailedOnSecondRoundWithStatus:status]; });
return;
}
Now both rounds of parallel requests have finished, so we can notify the main thread of success:
[self complexFlowSucceeded];
});
}
Overall, that seems like a pretty straightforward flow of control to me, and we just need to implement statusOfFirstRequestToSucceed and statusOfFirstRequestToFail. We can implement them with no extra threads. Since they are so similar, we'll make them both call on a helper function that does the real work:
static int statusOfFirstRequestToSucceed(NSArray *requestBlocks) {
return statusOfFirstRequestWithStatusPassingTest(requestBlocks, ^BOOL (int status) {
return status == 0;
});
}
static int statusOfFirstRequestToFail(NSArray *requestBlocks) {
return statusOfFirstRequestWithStatusPassingTest(requestBlocks, ^BOOL (int status) {
return status != 0;
});
}
In the helper function, I'll need a queue in which to run the completion blocks, to prevent race conditions:
static int statusOfFirstRequestWithStatusPassingTest(NSArray *requestBlocks,
BOOL (^statusTest)(int status))
{
dispatch_queue_t completionQueue = dispatch_queue_create("remote API completion", 0);
Note that I will only put blocks on completionQueue using dispatch_sync, and dispatch_sync always runs the block on the current thread unless the queue is the main queue.
I'll also need a semaphore, to wake up the outer function when some request has completed with a passing status, or when all requests have finished:
dispatch_semaphore_t enoughJobsCompleteSemaphore = dispatch_semaphore_create(0);
I'll keep track of the number of jobs not yet finished and the status of the last job to finish:
__block int jobsLeft = requestBlocks.count;
__block int outerStatus = 0;
When jobsLeft becomes 0, it means that either I've set outerStatus to a status that passes the test, or that all jobs have completed. Here's the completion block where I'll the work of tracking whether I'm done waiting. I do it all on completionQueue to serialize access to jobsLeft and outerStatus, in case the remote API dispatches multiple completion blocks in parallel (on separate threads or on a concurrent queue):
RemoteAPICompletionBlock completionBlock = ^(int status) {
dispatch_sync(completionQueue, ^{
I check to see if the outer function is still waiting for the current job to complete:
if (jobsLeft == 0) {
// The outer function has already returned.
return;
}
Next, I decrement the number of jobs remaining and make the completed job's status available to the outer function:
--jobsLeft;
outerStatus = status;
If the completed job's status passes the test, I set jobsLeft to zero to prevent other jobs from overwriting my status or singling the outer function:
if (statusTest(status)) {
// We have a winner. Prevent other jobs from overwriting my status.
jobsLeft = 0;
}
If there are no jobs left to wait on (because they've all finished or because this job's status passed the test), I wake up the outer function:
if (jobsLeft == 0) {
dispatch_semaphore_signal(enoughJobsCompleteSemaphore);
}
Finally, I release the queue and the semaphore. (The retains will be later, when I loop through the request blocks to execute them.)
dispatch_release(completionQueue);
dispatch_release(enoughJobsCompleteSemaphore);
});
};
That's the end of the completion block. The rest of the function is trivial. First I execute each request block, and I retain the queue and the semaphore to prevent dangling references:
for (void (^requestBlock)(RemoteAPICompletionBlock) in requestBlocks) {
dispatch_retain(completionQueue); // balanced in completionBlock
dispatch_retain(enoughJobsCompleteSemaphore); // balanced in completionBlock
requestBlock(completionBlock);
}
Note that the retains aren't necessary if you're using ARC and your deployment target is iOS 6.0 or later.
Then I just wait for one of the jobs to wake me up, release the queue and the semaphore, and return the status of the job that woke me:
dispatch_semaphore_wait(enoughJobsCompleteSemaphore, DISPATCH_TIME_FOREVER);
dispatch_release(completionQueue);
dispatch_release(enoughJobsCompleteSemaphore);
return outerStatus;
}
Note that the structure of statusOfFirstRequestWithStatusPassingTest is fairly generic: you can pass any request blocks you want, as long as each one calls the completion block and passes in an int status. You could modify the function to handle a more complex result from each request block, or to cancel outstanding requests (if you have a cancellation API).
While researching this myself I bumped into a port of Reactive Extensions to Objective-C. Reactive Extensions is like having the ability to querying a set of events or asynchronous operations. I know it has had a big uptake under .Net and JavaScript, and now apparently there is a port for Objective-C as well
https://github.com/blog/1107-reactivecocoa-for-a-better-world
Syntax looks tricky. I wonder if there is real world experience with it for iPhone development and if it does actually solve this issue elegantly.
I tend to wrap big nested block cluster f**** like you describe in subclasses of NSOperation that describe what the overall behaviour that your big nest block cluster f*** is actually doing (rather than leaving them littered throughout other code).
For example if your following code:
[remoteAPIWithURL:url1 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
[remoteAPIWithURL:url3 success:^(int status){
[remoteAPIWithURL:url2 success:^(int status){
//succes!!!
}];
}];
}];
}];
is intended to get an authorise token and then sync something perhaps it would be an NSAuthorizedSyncOperation… I'm sure you get the gist. Benefits of this are nice tidy bundles of behaviour wrapped up in a class with one place to edit them if things change down the line. My 2¢.
In NSDocument the following methods are available for serialization:
Serialization
– continueActivityUsingBlock:
– continueAsynchronousWorkOnMainThreadUsingBlock:
– performActivityWithSynchronousWaiting:usingBlock:
– performAsynchronousFileAccessUsingBlock:
– performSynchronousFileAccessUsingBlock:
I'm just digging into this, but it seems like this would be a good place to start.
Not sure if that is want you where looking for? Though all objects in the array need different times to complete the all appear in the order the where submitted to the queue.
typedef int(^SumUpTill)(int);
SumUpTill sum = ^(int max){
int i = 0;
int result = 0;
while (i < max) {
result += i++;
}
return result;
};
dispatch_queue_t queue = dispatch_queue_create("com.dispatch.barrier.async", DISPATCH_QUEUE_CONCURRENT);
NSArray *urlArray = #[ [NSURL URLWithString:#"http://www.google.com"],
#"Test",
[sum copy],
[NSURL URLWithString:#"http://www.apple.com"]
];
[urlArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
dispatch_barrier_async(queue, ^{
if ([obj isKindOfClass:[NSURL class]]) {
NSURLRequest *request = [NSURLRequest requestWithURL:obj];
NSURLResponse *response = nil;
NSError *error = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"index = %d, response=%# error=%#", idx, response, error);
}
else if ([obj isKindOfClass:[NSString class]]) {
NSLog(#"index = %d, string %#", idx, obj);
}
else {
NSInteger result = ((SumUpTill)obj)(1000000);
NSLog(#"index = %d, result = %d", idx, result);
}
});
}];
I use the Reachability class to know if I have an internet connection available. The problem is when wifi is available but not internet, the - (NetworkStatus) currentReachabilityStatus method take too much time.
my code:
Reachability* reachability = [Reachability reachabilityWithHostName:#"www.apple.com"];
NetworkStatus remoteHostStatus = [reachability currentReachabilityStatus];
The application "freeze" temporarily on the second line. How to define the maximum time for this waiting ?
I don't think so. But more importantly, I don't think you'd want to if you could (you may get false positives). Let Reachability run it's course.
If you look at the Reachability demo project, the notion isn't to invoke reachabilityWithHostName and check currentReachabilityStatus when you need the Internet. You invoke currentReachabilityStatus at during your app delegate's didFinishLaunchingWithOptions, set up a notification, and Reachability will tell you when the Internet connectivity has changed. I find that subsequent checks to currentReachabilityStatus are plenty fast (regardless of connectivity) when I (a) setup reachability at startup; but (b) check for connectivity in a just-in-time manner.
And if you absolutely need to start your processing immediately, then the question is whether you can push that into the background (e.g. dispatch_async()). E.g., my app retrieves updates from the server, but because that's happening in the background, neither me nor my user are aware of any delays.
I was having issues with the same thing but I found a way to specify a timeout. I replaced this method inside the Reachability Class from Apple.
- (NetworkStatus)currentReachabilityStatus
{
NSAssert(_reachabilityRef != NULL, #"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
//NetworkStatus returnValue = NotReachable;
__block SCNetworkReachabilityFlags flags;
__block BOOL timeOut = NO;
double delayInSeconds = 5.0;
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(delay, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
timeOut = YES;
});
__block NetworkStatus returnValue = NotReachable;
__block BOOL returned = NO;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
{
if (_alwaysReturnLocalWiFiStatus)
{
returnValue = [self localWiFiStatusForFlags:flags];
}
else
{
returnValue = [self networkStatusForFlags:flags];
}
}
returned = YES;
});
while (!returned && !timeOut) {
if (!timeOut && !returned){
[NSThread sleepForTimeInterval:.02];
} else {
break;
}
}
return returnValue;
}
My app is crashing in iOS 5 because I have some code that is calling UIKit instances from a secondary thread. You know you have this problem when you see the following error:
bool _WebTryThreadLock(bool), 0x811bf20: Multiple locks on web thread not allowed! Please file a bug. Crashing now…
So my question is what are some ways that I can find the code that is calling the UIKit instances from a secondary thread?
Here are some things I’ve tried already:
Commented out blocks that could be violating the rule
Added assert([NSThread isMainThread]) in places that might be processing in secondary thread
Added a symbolic breakpoint for _WebTryThreadLock
These things have helped me to find problem areas. However, in my final crash the _WebTryThreadLock breakpoint has no stack trace in any of the other threads. So, how I can find the code that causing the problem without a stack trace?
Thanks for your time!
Your assert() is probably the most valuable tool in this. I've been known to put a similar assertion at the beginning of every method in my Controller classes. If that doesn't find it, I add the assertion to my View classes. If that doesn't find it, I add it to any Model classes that I think are main-thread only.
To #craig's comment, the fact that it claims to be an internal bug might be accurate. But I think you're on the right path to closely examine your own code first.
I adapted the PSPDFUIKitMainThreadGuard.m to allow one to not have to worry about these things. Here: https://gist.github.com/k3zi/98ca835b15077d11dafc :
#import <objc/runtime.h>
#import <objc/message.h>
// Compile-time selector checks.
#define PROPERTY(propName) NSStringFromSelector(#selector(propName))
// A better assert. NSAssert is too runtime dependant, and assert() doesn't log.
// http://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html
// Accepts both:
// - PSPDFAssert(x > 0);
// - PSPDFAssert(y > 3, #"Bad value for y");
#define PSPDFAssert(expression, ...) \
do { if(!(expression)) { \
NSLog(#"%#", [NSString stringWithFormat: #"Assertion failure: %s in %s on line %s:%d. %#", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:#"" __VA_ARGS__]]); \
abort(); }} while(0)
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Helper for Swizzling
BOOL PSPDFReplaceMethodWithBlock(Class c, SEL origSEL, SEL newSEL, id block) {
PSPDFAssert(c && origSEL && newSEL && block);
Method origMethod = class_getInstanceMethod(c, origSEL);
const char *encoding = method_getTypeEncoding(origMethod);
// Add the new method.
IMP impl = imp_implementationWithBlock(block);
if (!class_addMethod(c, newSEL, impl, encoding)) {
NSLog(#"Failed to add method: %# on %#", NSStringFromSelector(newSEL), c);
return NO;
}else {
// Ensure the new selector has the same parameters as the existing selector.
Method newMethod = class_getInstanceMethod(c, newSEL);
PSPDFAssert(strcmp(method_getTypeEncoding(origMethod), method_getTypeEncoding(newMethod)) == 0, #"Encoding must be the same.");
// If original doesn't implement the method we want to swizzle, create it.
if (class_addMethod(c, origSEL, method_getImplementation(newMethod), encoding)) {
class_replaceMethod(c, newSEL, method_getImplementation(origMethod), encoding);
}else {
method_exchangeImplementations(origMethod, newMethod);
}
}
return YES;
}
// This installs a small guard that checks for the most common threading-errors in UIKit.
// This won't really slow down performance but still only is compiled in DEBUG versions of PSPDFKit.
// #note No private API is used here.
__attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) {
#autoreleasepool {
for (NSString *selStr in #[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) {
SEL selector = NSSelectorFromString(selStr);
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:#"pspdf_%#", selStr]);
if ([selStr hasSuffix:#":"]) {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) {
if(!NSThread.isMainThread){
dispatch_async(dispatch_get_main_queue(), ^{
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
});
}else{
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
}
});
}else {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) {
if(!NSThread.isMainThread){
dispatch_async(dispatch_get_main_queue(), ^{
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}else
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}
}
}
}
It automatically kicks calls into the main thread and thus you wouldn't even have to do anything but plop the code in.
This problem comes because you want to access to UI from secondary thread somehow, it can from webview of whatever else. It is not permitted because UIKit is not thread safe and can be accessed only from MainThread.
The very first thing you can do is to change your thread call to [self performSelectorOnMainThread:#selector(myMethod) withObject:nil waitUntilDone:NO]; (look for documentation).
In case when you have no other choice you can use GCD(Grand Central Dispathc)...
This code (just add to project and compile this file without ARC) causes assertions on UIKit access outside the main thread: https://gist.github.com/steipete/5664345
I've just used it to pickup numerous UIKit/main thread issues in some code I've just picked up.