How to setup reachability test for specific domain through AFNetworking? - ios

AFNetworkReachabilityManager *mgr=[AFNetworkReachabilityManager sharedManager];
[mgr startMonitoring];
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
//NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
if ([AFNetworkReachabilityManager sharedManager].reachable) {
NSLog(#" ONLINE");
}
else
{
NSLog(#"OFFLINE");
}
}];
This is how I tested reachability through AFNetworking now! How to check reachability in specific domain? And how does AFNetworking uses to test the reachability ?
[AFNetworkReachabilityManager managerForDomain:#"www.google.com"]; didn't work

Couple of things.
First, you really should configure the manager before starting monitoring. In this case this means you should call setReachabilityStatusChangeBlock before calling startMonitoring.
Second, when you're creating new AFNetworkReachabilityManager by using managerForDomain:, you are responsible for managing lifetime of the object. If you use code above with ARC enabled, mgr will be deallocated as soon as it goes out of scope meaning that there will be no manager to monitor reachability. One solution is to make mgr an instance variable of a class, e.g. an application delegate.

/**
Creates and returns a network reachability manager for the specified domain.
#param domain The domain used to evaluate network reachability.
#return An initialized network reachability manager, actively monitoring the specified domain.
*/
+ (instancetype)managerForDomain:(NSString *)domain;
this is from the afnetworking source code,
to monitor a specified domain, just create a reachability manager for that domain using this class method. like this
AFNetworkReachabilityManager *mgr= [AFNetworkReachabilityManager managerForDomain:#"www.google.com"];

Related

CKModifyRecordsOperation modifyRecordsCompletionBlock not being called

I'm using CKModifyRecordsOperation to save a set of records and if I have internet connection all works well and completion block is being called. But when I don't have connection the completion block is not being called and I don't get any information that my operations failed.
I'm using the following code in completion block
modifyOperations.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *error)
{
if(error){
NSLog(#"Error: %#", error.localizedDescription);
}
item.creatorRecordId = record.recordID;
};
and then I'm performing operation using
[self.publicDB addOperation:modifyOperations];
Any ideas how can I get an information if the operation failed for example in the case where there is no internet connection?
CloudKit operations have their qualityOfService property set to NSQualityOfServiceUtility by default.
Operations that use NSQualityOfServiceUtility or NSQualityOfServiceBackground may be marked as using discretionary network requests. The system can hold discretionary network requests if network connectivity is poor, so you might not get a response from the server until conditions improve and the system sends the request.
If you'd like your request to be sent immediately in all cases, set CKOperation.qualityOfService to NSQualityOfServiceUserInitiated or NSQualityOfServiceUserInteractive.

Check if iOS device's internet connection is actually working [duplicate]

This question already has an answer here:
Determine whether iPhone is really connected to the internet or just behind a restricted hotspot
(1 answer)
Closed 7 years ago.
There are loads of questions on here about finding an active internet connection in an app, but none work if you are on a 3g connection and you have no data credit, or if you are on a WiFi network at a hotel that automatically redirects to a log in page and you have yet to enter the password. That kind of situation.
What is the fastest way to check if the internet connection is actually operational?
You can use AFNetworkReachabilityManager class in AFNetworking.
https://github.com/AFNetworking/AFNetworking
above link will help you out in setting things. This will provide you with continuous network check as per your requirement. Here is few line of code:
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));
}];
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
The best way to accomplish this, not using Reachability or any other API, is by creating a NSURL and to try to receive data from it. For the bad connection I added a timeout of 20sec.
Like:
- (void)checkConnection //Run this on a side queue, never on a main queue
{ NSURL *checkURL = [NSURL URLWithString:#"http://www.apple.com"];
NSURLRequest *lRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:checkURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:20.0];
NSData *data = [NSData dataWithContentsOfURL:lRequest];
if (data)
{
connected = YES;
}
else
{
connected = NO;
}
}
That would check if a specific website is reachable and set a timeout which indicates a slow network connection.
This code could have errors, as I haven't used/tried it yet! Comment this answer if there are any.

Custom NSURLProtocol added to configuration.protocolClasses prevents working of default url protocols

I try to add a custom NSURLProtocol to a NSURLSession in order to serve test data for some calls, while providing the normal internet connectivity for all other calls. I need to do this by adding the NSURLProtocol to the session configuration's protocolClasses, as the session resides in a library that is included in the project.
For some reason my setup does deliver the test data right when my custom protocol takes the request by returning true for the canInitWithRequest call, but for all other requests (when it returns false) the default protocols that are still in the protocolClasses behind my custom protocol get the request and even return true on the canInitWithRequest call, but they never send the request to the internet and deliver a request timeout after 30 seconds instead. When I remove my custom protocol from the protocolClasses, everything works fine - just my test data is not served anymore, of course.
This is the code I use for installing the protocol:
NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
NSMutableArray* protocols = [NSMutableArray arrayWithArray:sessionConfiguration.protocolClasses];
[protocols insertObject:[MyProtocol class] atIndex:0];
sessionConfiguration.protocolClasses = protocols;
mySession = [NSURLSession sessionWithConfiguration:sessionConfiguration];
When I register the custom protocol with [NSURLProtocol registerClass:[MyProtocol class]], the fallthrough does work, but as written I can't use this approach in my project.
Any idea on why this is not working correctly?
Firstly there is a misprint in your code snippet, it should be protocols instead of array variable. ))
I think that in case of custom protocol, it makes sense to see protocol client and so on( propertyFoKey: inRequest:)
Is the method startLoading(or stopLoading) is called?
Ah, I have re read your question.
In case of [NSURLProtocol registerClass] , the custom class, if being the latest registered, will handle URL scheme.
In your case it seems that there is another(void) protocol that handles the request.

XMPPFramework - Auto Accept of Presence Subscription Requests

I think the title is illustrating enough, but here's the story:
I'm new to XMPPFramework for iOS, and I want to set my client to automatically accept any subscription request it receives. So that other clients can see this client's presence status, when they request it.
According to developer comments In XMPPRoster.h file, there's this method which is called when a subscription request is received:
/**
* Sent when a presence subscription request is received.
* That is, another user has added you to their roster,
* and is requesting permission to receive presence broadcasts that you send.
*
* The entire presence packet is provided for proper extensibility.
* You can use [presence from] to get the JID of the user who sent the request.
*
* The methods acceptPresenceSubscriptionRequestFrom: and rejectPresenceSubscriptionRequestFrom: can
* be used to respond to the request.
**/
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
But it is not implemented in XMPPRoster.m. So I implemented it as following :
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence
{
[self acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Since I'm new to XMPPFramework I dunno if I have done anything wrong, but I still cannot get this client's presence in other clients.
I also have seen similar topics like Accept buddy request in xmpp client iphone or Xmpp Accepting buddy request but the solution does not seem to be even related !
Any suggestions is really appreciated.
Thanks.
You did it wrong. You do not have to implement something in XMPPRoster.m or other library files.
This function
- (void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence;
is a callback fired when your xmpp client receives presence subscription request. If you want to execute some code when this callback fired you have to implement a protocol called XMPPRosterDelegate. Protocol is a feature like interface in Java and C# or like abstract class in C++. You have to have a class that inherits from this XMPPRosterDelegate and finally implements this function (and other functions if you want so).
If you want to autoaccept all requests you have to implement your protocol function implementation like this:
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Also roster object got to know who is its delegate (an object who implements XMPPRosterDelegate), cause if you want to send someone a message you have to know two things: target and selector. Selector is specified in protocol. Target is a delegate property. You have to set roster's delegate during its initialization. In my code I added line
[xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
before line
[xmppRoster activate:xmppStream];
Of course self implements XMPPRosterDelegate and especially has this piece of code
-(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
[sender acceptPresenceSubscriptionRequestFrom:[presence from] andAddToRoster:YES];
}
Good luck and sorry for long post.

Switch between different API hosts

I'm working on an app which primarily works with an API that will be installed in an internal system. The API is also accessible via the public internet. The client wants to allow users to enter both an internal and external (public internet) URL that the app will then connect to depending on availability of the internal and external URLs.
The app is basically done with the exception that it currently connects to the internal URL only for all it's API calls. I'm using AFNetworking with block-based completion/failure invocations for each API call.
Based on the logic that we have designed, the app will always check for the API's availability by querying for the server's current time. This is done by calling http://internal_url/api/time. If this API fails to return an appropriate respond, we'll switch to the external URL http://external_url/api/time and call the same API on that URL. If both fails, the app will inform the user accordingly and not perform any other queries to the API.
Without revealing too much, here's some code on how I the API calls are currently setup:
- (void)someAPIMethodCall:(NSDictionary *)parameters completionBlock:block failure:block {
// query /api/time and return the URL (internal/external) that is currently up
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:<url returned from above query>];
[client operationWithSuccess:block failure:block];
}
So my question would be: what is the best way to get the query /api/time method above to work? Obviously, this method needs to complete and return either the internal/external URL so that the subsequent actual API query could use. AFAIK, AFNetworking calls are block-based so it will return before the above /api/time returns. I've also thought of a separate class that uses NSURLConnection synchronously which will block the main-thread while it waits for the /api/time to return.
I'd like to tell you to simply use the same URL internally and externally (via DNS) but that's not what you want.
I think you're asking how to conditionally call the other url.
You want someAPIMethodCall to be asynchronous... so you don't want to block on the call to checking for the correct api to call.
Aside from caching the results so you don't have to do this every time, you simply want to call another block based method of your own that has a completion block which passes IN a parameter of the URL to call for your real query.
- (void)someAPIMethodCall:(NSDictionary *)parameters completionBlock:(void (^)(void))succesBlock failure((^)(void)):failureBlock {
[self callBlockWithMyApiUrl:^(NSString *apiUrl){
AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:apiUrl];
[client operationWithSuccess:successBlock failure:failureBlock];
} onFailure:^{
failureBlock
}
}
- (NSString *)callBlockWithMyApiUrl:(NSString * (^)(void))success (void (^)(void))failure
{
// Your code to test for the working URI
// If you're doing it this way, I'd suggest caching the result.
// Subscribe to networking interface changes to dump the cache.
}

Resources