Why i get timeout erros when page is not available - objective-c

I use NSString method initWithContentsOfURL:usedEncoding:error: to get content of some page. I notice, when page that i try to access is not exist this method is executed long time and then fail with timeout error. I tried to use NSURLRequest and NSURLConnection classes for the same purposes, but get the same result - execution long time and then timeout error.
When i try to open the same page in browser, i get response more quickly and it returns page is not available error.
It looks like cocoa methods don't do a dns resolution for page name, or they have longer timeout for that operation.
So my question, does cocoa method that i use do dns resolve? How to do that if they didn't?
Samples of code i use:
NSURL* url = [NSURL URLWithString:#"http://unexisting.domain.local"];
NSError* err = nil;
NSString* content = [NSString stringWithContentsOfURL:url usedEncoding:nil error:&err];
if (err) {
NSLog(#"error: %#", err);
} else {
NSLog(#"content: %#", content);
}
NSURL* url = [NSURL URLWithString:#"http://unexisting.domain.local"];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
NSURLResponse* response = nil;
NSError* err = nil;
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if (err) {
NSLog(#"error: %#", err);
} else {
NSString* content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"content: %#", content);
}
Thanks!

Gene M. answered how to do that with using of SCNetworkReachability. Here is sample code:
bool success = false;
const char *host_name = [#"stackoverflow.com"
cStringUsingEncoding:NSASCIIStringEncoding];
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL,
host_name);
SCNetworkReachabilityFlags flags;
success = SCNetworkReachabilityGetFlags(reachability, &flags);
bool isAvailable = success && (flags & kSCNetworkFlagsReachable) &&
!(flags & kSCNetworkFlagsConnectionRequired);
if (isAvailable) {
NSLog(#"Host is reachable: %d", flags);
}else{
NSLog(#"Host is unreachable");
}

It's definitely good practice to monitor the reachability (device connectivity) and react to it as noted above.
You can also implement the NSURLConnectionDelegate protocol and its methods such as
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"**ERROR** %#", error);
// Respond to error
}
If you're not connected you should get an NSURLConnection error code of 999 and NSURLErrorCancelled = -999 and/or a NSURLErrorNotConnectedToInternet = -1009 if you're not connected, etc. At least you'd have a report back of what's going on.
Docs:
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Constants/Reference/reference.html

Related

Play Last recording in Watchkit OS 2

i use the sample codes from apple for recording and playing the last recording
but i can't play the last recording
here are the codes
- (IBAction)playLastRecording {
// Present the media player controller for the last recorded URL.
NSDictionary *options = #{
WKMediaPlayerControllerOptionsAutoplayKey : #YES
};
[self presentMediaPlayerControllerWithURL:self.lastRecordingURL options:options completion:^(BOOL didPlayToEnd, NSTimeInterval endTime, NSError * __nullable error) {
if (!didPlayToEnd) {
NSLog(#"The player did not play all the way to the end. The player only played until time - %.2f.", endTime);
}
if (error) {
NSLog(#"There was an error with playback: %#.", error);
}
}];
}
and here is the error
i think we need to use the NSbundle and nsurl connection but how
to use for self.lastRecordingURL
please writing the correct codes for this problems
Optional(Error Domain=com.apple.watchkit.errors Code=4 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (1), NSUnderlyingError=0x17d9bf50 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}, NSLocalizedDescription=The operation could not be completed})
I had this problem. Make sure that the audio data is saved to the Apps Group correctly with the correct extension of the file.
If you are trying to record the audio file use the following codes.
- (void)startRecording
{
// Creating a path for saving the recorded audio file.
// We have to write the files to the shared group folder, as this is the only place both the app and extension can see.
NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:APP_GROUP_IDENTIFIER];
NSURL *outputURL = [container URLByAppendingPathComponent:#"AudioFile.m4a"];
// Setting the recorder options.
NSDictionary *dictMaxAudioRec = #{#"WKAudioRecorderControllerOptionsMaximumDurationKey":MAX_REC_DURATION};
// Presenting the default audio recorder.
[self presentAudioRecorderControllerWithOutputURL:outputURL preset:WKAudioRecorderPresetWideBandSpeech options:dictMaxAudioRec completion:^(BOOL didSave, NSError * error) {
if(didSave)
{
// Successfully saved the file.
NSURL *extensionDirectory = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject;
NSUInteger timeAtRecording = (NSUInteger)[NSDate timeIntervalSinceReferenceDate];
NSString *dirName = [NSString stringWithFormat:#"AudioFile%d/",timeAtRecording];
NSURL *outputExtensionURL = [extensionDirectory URLByAppendingPathComponent:dirName];
// Move the file to new directory.
NSError *moveError;
BOOL success = [[NSFileManager defaultManager] moveItemAtURL:outputURL toURL:outputExtensionURL error:&moveError];
if (!success) {
NSLog(#"Failed to move the outputURL to the extension's documents direcotry: %#", moveError);
}
else {
NSData *audioData = [NSData dataWithContentsOfURL:outputExtensionURL];
NSLog(#"Actual Audio Data length: %lu", (unsigned long)audioData.length);
if(audioData.length)
{
// We have a valid audio data,do what ever you want to do with this data
}
}
}
else
{
// Something went wrong.
NSLog(#"%s - %#",__PRETTY_FUNCTION__,error);
}
}];
}
Or if you are trying to play a video that you have downloaded from other source or passed from the paired phone, write the audio data first to the App Groups with file extension. The following codes may help you for that.
- (void)writeAudioToAppGroupsWithData:(NSData *)audioData
{
// Writing the audio data to the App Groups
NSURL *containerURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:APP_GROUP_IDENTIFIER];
containerURL = [containerURL URLByAppendingPathComponent:[NSString stringWithFormat:DIRECTORY_PATH]];
[audioData writeToURL:containerURL atomically:YES];
}
In this case make sure that your DIRECTORY_PATH is Library/Caches/filename.extension.
Eg: Library/Caches/Audio.mp3
For playing the saved audio use the following codes.
- (void)playAudio
{
// Playing the audio from the url using the default controller
[self presentMediaPlayerControllerWithURL:[self getAudioUrl] options:nil completion:^(BOOL didPlayToEnd, NSTimeInterval endTime, NSError * _Nullable error) {
NSLog(#"Error = %#",error);
}];
}
You can get the audio url from the App Groups.
- (NSURL *)getAudioUrl
{
// Getting the audio url from the App Groups
NSURL *container = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:APP_GROUP_IDENTIFIER];
NSURL *outputURL = [container URLByAppendingPathComponent:[NSString stringWithFormat:DIRECTORY_PATH]];
return outputURL;
}
Hope this will fix your issue.

Can't create IPSEC connection using NEVPNManager on iOS

I'm trying to create an IPSEC VPN connection in my iOS app.
My code for setting up the configuration looks like this:
-(void)setUpConfig
NEVPNManager *manager = [NEVPNManager sharedManager];
int status = manager.connection.status;
if (status == NEVPNStatusConnected) {
manager.connection stopVPNTunnel];
} else {
[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
NSError *startError;
if (error) {
NSLog(#"Load config failed [%#]", error.localizedDescription);
return;
}
NEVPNProtocolIPSec *p = (NEVPNProtocolIPSec *)self.manager.protocol;
if (!p) {
p = [[NEVPNProtocolIPSec alloc] init];
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"base64_encoded_cert" ofType:#"txt"];
NSString *certBase64String = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
NSString *certPassword = #"cert_import_password";
NSString *vpnUsername = #"myUsername";
NSString *vpnPassword = #"myPassword";
NSString *url = #"my.server.address";
// This saves my credentials to the keychain and returns a persistent keychain reference
NSData *passRef = [self addVPNCredentialsToKeychain:vpnUsername withPassword:vpnPassword];
p.username = vpnUsername;
p.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
p.serverAddress = url;
p.passwordReference = passRef;
p.identityData = [NSData dataWithBase64EncodedString:certBase64String];
p.identityDataPassword = certPassword;
p.disconnectOnSleep = NO;
p.useExtendedAuthentication = YES;
[manager setProtocol:p];
[manager setOnDemandEnabled:NO];
[manager setLocalizedDescription:#"My VPN"];
[manager saveToPreferencesWithCompletionHandler:^(NSError *error) {
if(error) {
NSLog(#"Save error: %#", error);
} else {
NSLog(#"Saved!");
}
}];
}];
}
}
-(NSData*)addVPNCredentialsToKeychain:(NSString*)username withPassword:(NSString*)password
{
NSMutableDictionary *keychainItem = [NSMutableDictionary dictionary];
NSData *encodedIdentifier = [username dataUsingEncoding:NSUTF8StringEncoding];
keychainItem[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
keychainItem[(__bridge id)kSecAttrDescription] = #"A password used to authenticate on a VPN server";
keychainItem[(__bridge id)kSecAttrGeneric] = encodedIdentifier;
keychainItem[(__bridge id)kSecAttrAccount] = encodedIdentifier;
keychainItem[(__bridge id)kSecAttrService] = [[NSBundle mainBundle] bundleIdentifier];
keychainItem[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
keychainItem[(__bridge id)kSecReturnPersistentRef] = #YES;
CFTypeRef typeResult = nil;
OSStatus sts = SecItemCopyMatching((__bridge CFDictionaryRef)keychainItem, &typeResult);
NSLog(#"Error Code: %d", (int)sts);
if(sts == noErr) {
NSData *theReference = (__bridge NSData *)typeResult;
return theReference;
} else {
keychainItem[(__bridge id)kSecValueData] = [password dataUsingEncoding:NSUTF8StringEncoding]; //Our password
OSStatus sts = SecItemAdd((__bridge CFDictionaryRef)keychainItem, &typeResult);
NSLog(#"Error Code: %d", (int)sts);
NSData *theReference = (__bridge NSData *)(typeResult);
return theReference;
}
return nil;
}
I then attempt to open a VPN connection like so:
-(void)connect
NEVPNManager *manager = [NEVPNManager sharedManager];
[manager loadFromPreferencesWithCompletionHandler:^(NSError *error) {
NSError *startError;
[manager.connection startVPNTunnelAndReturnError:&startError];
if(startError) {
NSLog(#"Start error: %#", startError.localizedDescription);
}
}];
}
And this does work under most conditions. The problem I am experiencing is that after factory restoring a device (on iOS 8, of course), and attempting to go through this setup and connection, my profile installs just fine, but the VPN fails to connect. In fact, my interpretation is that it is failing to attempt to connect.
After factory restoring a device and attempting to connect using my method, the following shows up in the device logs:
<Notice>: NESMLegacySession[MyVPN:BB73C098-B22E-46D3-9491-2A6D9F559F8F]: Received a start command from VPNApp[256], but start was rejected
Going into the Settings app and attempting to manually toggle the VPN using the switch under "Bluetooth" results in the switch turning on for a split second and then immediately going by to off. In this case, the following log is produced:
<Warning>: -[VPNBundleController _vpnNetworkingIsDisabled]: Airplane mode: 0, WiFi Enabled: 1
In both cases, no error dialog is produced when the VPN fails to start connecting - just the logs.
I can get around this problem by navigating to Settings > General > VPN. Once having just gone to that page (i.e. Not toggling VPN there), I can then control VPN just fine. Even going to that page before a VPN configuration is even installed results in me being able to connect just fine after installing a configuration.
My goal is to be able to start the VPN connection without having to first go to that VPN page in Settings. Can anyone shed some light on the situation? It seems to me like I'm missing something to first enable VPN connections.
This appears because VPN configuration stayed disabled by default for initial VPN connection.
You must enable VPN before saveToPreferencesWithCompletionHandler.
[[NEVPNManager sharedManager] setEnabled:YES];
Example:
[[NEVPNManager sharedManager] loadFromPreferencesWithCompletionHandler: ^(NSError *error) {
if (error) {
NSLog(#"Load error: %#", error);
}
else {
// No errors! The rest of your codes goes here...
NEVPNProtocolIPSec *p = [[NEVPNProtocolIPSec alloc] init];
p.serverAddress = #"VPN SERVER ADDRESS";
p.authenticationMethod = NEVPNIKEAuthenticationMethodCertificate;
p.localIdentifier = #"Local identifier";
p.remoteIdentifier = #"Remote identifier";
p.useExtendedAuthentication = YES;
p.identityData = [NSData dataWithBase64EncodedString:certBase64String];;
p.identityDataPassword = #"identity password";
p.disconnectOnSleep = NO;
// Set protocol
[[NEVPNManager sharedManager] setProtocol:p];
// Set on demand
NSMutableArray *rules = [[NSMutableArray alloc] init];
NEOnDemandRuleConnect *connectRule = [NEOnDemandRuleConnect new];
[rules addObject:connectRule];
[[NEVPNManager sharedManager] setOnDemandRules:rules];
// Set localized description
[[NEVPNManager sharedManager] setLocalizedDescription:#"Description"];
// Enable VPN
[[NEVPNManager sharedManager] setEnabled:YES];
// Save to preference
[[NEVPNManager sharedManager] saveToPreferencesWithCompletionHandler: ^(NSError *error) {
NSLog(#"Save VPN to preference complete");
if (error) {
NSLog(#"Save to preference error: %#", error);
}
}];
}
}];

Native Facebook/iOS6 integration: Cocoa error 3840 when trying to get profile picture

I am currently using only Social.framework (no FacebookSDK) and getting starting with requesting and getting access to basic user data. Here's all the code I have (with a few properties declared outside, as you'll notice). Everything works fine in terms of getting the right permissions, but I'm getting the following output error when asking for user's profile picture:
2013-01-27 21:28:44.324 TestApp[9230:1a703] Account saved to accountStore
2013-01-27 21:28:45.002 TestApp[9230:1d603] (null)
2013-01-27 21:28:45.003 TestApp[9230:1d603] Request error: The operation couldn’t be completed. (Cocoa error 3840.)
And here is the code:
- (IBAction)btnFbLoginPressed:(id)sender
{
ACAccountType *fbAccountType = [self.accountStore accountTypeWithAccountTypeIdentifier: ACAccountTypeIdentifierFacebook];
NSArray *permissions = #[#"email"];
self.requestAccessOptions = #{ACFacebookAppIdKey:FB_API_KEY, ACFacebookPermissionsKey:permissions, ACFacebookAudienceKey:ACFacebookAudienceOnlyMe};
[self.accountStore requestAccessToAccountsWithType:fbAccountType options:self.requestAccessOptions completion:^(BOOL granted, NSError *e) {
if (granted && e == nil) {
NSArray *readPermissions = #[#"user_photos"];
NSDictionary *readAcccessOptions = #{ACFacebookAppIdKey:FB_API_KEY, ACFacebookPermissionsKey:readPermissions, ACFacebookAudienceKey:ACFacebookAudienceOnlyMe};
[self.accountStore requestAccessToAccountsWithType:fbAccountType options:readAcccessOptions completion:^(BOOL granted, NSError *e) {
if (granted && e == nil) {
NSArray *accounts = [self.accountStore accountsWithAccountType:fbAccountType];
self.facebookAccount = [accounts lastObject];
[self.accountStore saveAccount:self.facebookAccount withCompletionHandler:^(BOOL success, NSError *error) {
if (error != nil || !success) {
NSLog(#"Error saving account to accountStore: %#", error.localizedDescription);
} else {
NSLog(#"Account saved to accountStore");
}
}];
NSString *uid = [NSString stringWithFormat:#"%#", [[self.facebookAccount valueForKey:#"properties"] valueForKey:#"uid"]];
NSString *url = [NSString stringWithFormat:#"https://graph.facebook.com/%#/picture", uid];
NSURL *profilePictureURL = [NSURL URLWithString:url];
SLRequest *profilePictureRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:profilePictureURL parameters:nil];
profilePictureRequest.account = self.facebookAccount;
[profilePictureRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *e)
{
NSDictionary *responseDataDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&e];
NSLog(#"%#", responseDataDictionary);
if (e != nil) {
NSLog(#"Request error: %#", e.localizedDescription);
} else {
}
}];
} else {
NSLog(#"Read permissions request error: %#", e.localizedDescription);
}
}];
} else {
NSLog(#"Basic permissions request error: %#", e.localizedDescription);
}
}];
}
You can see that the reponseDataDictionary is null and something happens when parsing the data. I noticed a couple of other threads on SO about the same error code, but no luck so far. My guess is that either 1) there's something wrong with my Facebook code, or 2) I'm parsing the data incorrectly. Any help's appreciated!
Note: I would like to stick to using the Social/Account frameworks only.
UPDATE: Slight modification thanks to a suggestion in the comments.
Changed code:
[profilePictureRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *e)
{
NSLog(#"Request error value: %#", e.localizedDescription);
NSError *jsonError = nil;
NSDictionary *responseDataDictionary = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingAllowFragments error:&jsonError];
NSLog(#"Response data dictionary value: %#", responseDataDictionary);
if (jsonError != nil) {
NSLog(#"Serialization error: %#", jsonError.localizedDescription);
} else {
NSLog(#"Serialization successful");
}
}];
Output:
2013-01-28 18:55:16.265 TestApp[9565:1ae03] Account saved to accountStore
2013-01-28 18:55:17.640 TestApp[9565:1b503] Request error value: (null)
2013-01-28 18:55:17.640 TestApp[9565:1b503] Response data dictionary value: (null)
2013-01-28 18:55:17.642 TestApp[9565:1b503] Serialization error: The operation couldn’t be completed. (Cocoa error 3840.)
The profilePictureRequest is returning an image and not JSON. Use + (CIImage *)imageWithData:(NSData *)data to convert the response to an image.

Calling a asp.net webservice from objective c to return data in JSON format with parameters

<ServiceContract()> _
Public Interface IGetEmployees
<OperationContract()> _
<WebInvoke(Method:="GET", ResponseFormat:=WebMessageFormat.Json,BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="json/contactoptions/?strCustomerID={strCustomerID}")> _
Function GetAllContactsMethod(strCustomerID As String) As List(Of NContactNames)
End Interface
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function GetAllContactsMethod(strCustomerID As String) As List(Of NContactNames) Implements IGetEmployees.GetAllContactsMethod
Utilities.log("Hit get all contacts at 56")
Dim intCustomerID As Integer = Convert.ToInt32(strCustomerID)
Dim lstContactNames As New List(Of NContactNames)
'I add some contacts to the list.
Utilities.log("returning the lst count of " & lstContactNames.Count)
Return lstContactNames
End Function
So when i write the above code and call it in the browser like this http://xyz-dev.com/GetEmployees.svc/json/contactoptions/?strCustomerID=123 i get 10 rows as results in JSON format. That is as i intended. But when i call from objective c side it throws exception like this
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
My objective c code is:
NSString *strCustomerID = [NSString stringWithFormat:#"%i",123];
jUrlString = [NSString stringWithFormat:#"%#?strCustomerID=%#",#"https://xyz-dev.com/GetEmployees.svc/json/contactoptions/",strCustomerID];
NSLog(#"the jurlstring is %#",jUrlString);
NSURL *jurl = [NSURL URLWithString:jUrlString];
NSError *jError;
NSData *jData = [NSData dataWithContentsOfURL:jurl];
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:jData options:kNilOptions error:&jError];
NSLog(#"%#",json);
NSLog(#"Done");
Exception occurs at NSJSONSerialization line.
So this is sort of continuation to my question Web service method not hit when called via Objective C i changed my code little bit so I posted a new question. Is it the correct way i am writing the uritemplate on asp side?is it the right way i am calling on iOS side? Please let me know if you need more info. Thanks..
Your url does not seem to be correct. make sure it is correct.
You need to follow the NSURLConnectionDelegate to setup this service. Here is a some sample code I often reuse. You need to setup your connection, then properly process your data. I've created a delegate and notify on completion or error.
documentation: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
ex.
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#implementation JSONService
#synthesize delegate;
- (void)start{
dispatch_async(kBgQueue, ^{
NSError *error = nil;
NSURL *nsURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#?strCustomerID=%#",#"https://xyz-dev.com/GetEmployees.svc/json/contactoptions",strCustomerID]];
NSData* data = [NSData dataWithContentsOfURL:nsURL options:NSDataReadingUncached error:&error];
if (error) {
NSLog(#"%#", [error localizedDescription]);
[self notifyDelegateOfError:error];
} else {
NSLog(#"Data has loaded successfully.");
}
[self performSelectorOnMainThread:#selector(processData:) withObject:data waitUntilDone:YES];
});
}
- (void)cancel{
//TODO KILL THE SERVICE (GRACEFULLY!!!!!) -- ALLOW VC'S TO CANCEL THE SERVICE & PREVENT SEGFAULTS
}
- (id)initWithDelegate:(id<WebServiceDelegate>)aDelegate
{
self = [super init];
if (self) {
[self setDelegate:aDelegate];
}
return self;
}
- (void)processData:(NSData *)data{
//parse out the json data
NSError* error;
if(data == nil){
error = [NSError errorWithDomain:#"NO_DOMAIN" code:001 userInfo:nil];
[self notifyDelegateOfError:error];
return;
}
//EITHER NSDictionary = json or NSMutableArray = json
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
//NSArray *dataArray = [[json objectForKey:#"data"] objectForKey:#"current_condition"];
//... more parsing done here.
//NO ERRORS ALL DONE!
[self notifyDelegateOfCompletion];
}
- (void)notifyDelegateOfError:(NSError *)error{
[delegate webService:self didFailWithError: error];
}
- (void)notifyDelegateOfCompletion
{
if ([delegate respondsToSelector:#selector(webServiceDidComplete:)]) {
[delegate webServiceDidComplete:self];
}
}

HTTP server works in Cocoa application but not test case -- run loop issue?

I'm trying to add a GHUnit test case to this SimpleHTTPServer example. The example include a Cocoa application that works fine for me. But I can't duplicate the behavior in a test case.
Here is the test class:
#import <GHUnit/GHUnit.h>
#import "SimpleHTTPServer.h"
#interface ServerTest : GHTestCase
{
SimpleHTTPServer *server;
}
#end
#implementation ServerTest
-(void)setUpClass
{
[[NSRunLoop currentRunLoop] run];
}
- (NSString*)requestToURL:(NSString*)urlString error:(NSError**)error
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:1];
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error];
NSString *page = nil;
if (error == nil)
{
NSStringEncoding responseEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)[response textEncodingName]));
page = [[NSString alloc] initWithData:data encoding:responseEncoding];
[page autorelease];
}
return page;
}
- (void)testPortReuse
{
unsigned int port = 50001;
NSError *error = nil;
NSString *path, *url;
server = [[SimpleHTTPServer alloc] initWithTCPPort:port delegate:self];
sleep(10);
path = #"/x/y/z";
url = [NSString stringWithFormat:#"http://localhost:%u%#", port, path];
[self requestToURL:url error:&error];
GHAssertNil(error, #"%# : %#", url, error);
[server release];
}
- (void)processURL:(NSURL *)path connection:(SimpleHTTPConnection *)connection
{
NSLog(#"processURL");
}
- (void)stopProcessing
{
NSLog(#"stopProcessing");
}
#end
I've tried sending requests via NSURLRequest and also (during the sleep) via a web browser. The delegate methods -processURL and -stopProcessing are never called. The problem seems to be that [fileHandle acceptConnectionInBackgroundAndNotify] in SimpleHTTPServer -initWithTCPPort:delegate: is not causing any NSFileHandleConnectionAcceptedNotifications to reach the NSNotificationCenter -- so I suspect a problem involving run loops.
The problem seems to be with the NSFileHandle, not the NSNotificationCenter, because when [nc postNotificationName:NSFileHandleConnectionAcceptedNotification object:nil] is added to the end of initWithTCPPort:delegate:, the NSNotificationCenter does get the notification.
if (error == nil)
That should be:
if (data != nil)
error here is the passed-in pointer to an NSError* - it will only be nil if the caller passed nil instead of a reference to an NSError* object, which isn't what your -testPortReuse method does.
It would also be incorrect to dereference it (as in if (*error == nil)), because error arguments are not guaranteed to be set to nil upon error. The return value indicates an error condition, and the value returned in the error argument is only meaningful or reliable if there is an error. Always check the return value to determine if an error happened, then check the error parameter for details only if something did in fact go wrong.
In other words, as it's written above, your -requestToURL:error: method is incapable of handling success. Much like Charlie Sheen. :-)