Set UISwitches by JSON data? - objective-c

I want to set some UISwitches to values pulled in by a HTTP GET request. The request is working. However, since I'm fairly new to iOS programming I don't know how to go from having some JSON data to pulling it apart like in PHP.
This is what I currently have:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"viewdidload");
self.responseData = [NSMutableData data];
NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:#"http://www.test.api/setings"]];
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[mutableRequest addValue:_xAuthToken forHTTPHeaderField:#"X-Auth-Token"];
request = [mutableRequest copy];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
[switch1 setOn:1 animated:NO];
[switch2 setOn:1 animated:NO];
[switch3 setOn:1 animated:NO];
[switch4 setOn:1 animated:NO];
[switch5 setOn:1 animated:NO];
[switch6 setOn:1 animated:NO];
[switch7 setOn:0 animated:NO];
[switch8 setOn:1 animated:NO];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"didReceiveResponse");
[self.responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"didFailWithError");
NSLog([NSString stringWithFormat:#"Connection failed: %#", [error description]]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
NSLog(#"Succeeded! Received %d bytes of data",[self.responseData length]);
// convert to JSON
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];
// show all values
for(id key in res) {
id value = [res objectForKey:key];
NSString *keyAsString = (NSString *)key;
NSString *valueAsString = (NSString *)value;
NSLog(#"key: %#", keyAsString);
NSLog(#"value: %#", valueAsString);
}
// extract specific value...
NSArray *results = [res objectForKey:#"results"];
for (NSDictionary *result in results) {
NSString *icon = [result objectForKey:#"icon"];
NSLog(#"icon: %#", icon);
}
}
- (void)viewDidUnload {
[super viewDidUnload];
}
And this is what it's getting back from the server:
{"data":
{"setting1":"1",
"setting2":"1",
"setting3":"0",
"setting4":"0",
"setting5":"0",
"setting6":"0",
"setting7":"0",
"setting8":"0"}
}

Just convert the 1 or 0 number string to bool value and then set the switch state using it
//Declare this array of switches in your class header file
property(strong,nonatomic)NSArray *switches;
and initialize it in ViewDidLoad method
switches=[NSArray arrayWithObjects:switch1,switch2,switch3,switch4,switch5,switch6,switch7,switch8,nil];
// and in your - (void)connectionDidFinishLoading:(NSURLConnection *)connection method
NSError *myError = nil;
NSDictionary *res = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:&myError];
//get the array of settings and values from the data Object in your json
NSDictionary *switchValues=[res objectForKey:#"data"];
// show all values
NSUInteger *switchIndex=0;
//iterate and convert the value to bool and set the switch state using that value
for(id key in switchValues) {
id value = [switchValues objectForKey:key];
NSString *keyAsString = (NSString *)key;
NSString *valueAsString = (NSString *)value;
[[switches objectAtIndex:switchIndex] setOn:[valueAsString boolValue] animated:NO];
NSLog(#"key: %#", keyAsString);
NSLog(#"value: %#", valueAsString);
switchIndex++;
}

Related

NSURLConnection switch to NSURLSession returning 404 response

I am attempting to convert my project from using NSURLConnection to NSURLSession. However, after making the switch I cannot seem to get a response from the server. The returned response from the server is always 404.
My original code, using NSURLConnection:
#implementation RecorderManager
- (void)sendRequestToURL:(NSString*)url withData:(NSData*)postData forScreen:(NSString *)inScreenName
{
RecorderAsynchSubmit* delegate = [[RecorderAsynchSubmit alloc] initWithScreenName:inScreenName andURL:url];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:delegate];
}
#implementation RecorderAsynchSubmit
// Implementing NSURLConnectionDelegate, NSURLConnectionDataDelegate
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Handle error
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[httpResponse setLength:0];
httpResponseCode = [((NSHTTPURLResponse *) response) statusCode];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)httpdata
{
[httpResponse appendData:httpdata];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *responseString = [[[NSString alloc] initWithData:httpResponse encoding:NSUTF8StringEncoding] copy];
if (httpResponseCode == STATUS_CODE_VALID) { // response code for entry submitted
responseString = #"Submit Succeeded";
} else {
responseString = [NSString stringWithFormat:#"Your entry could not be submitted. Data has been stored locally. Error Message: %#", responseString];
}
[[NSNotificationCenter defaultCenter]
postNotificationName:#"submissionCompleteEvent"
object:[[RecorderNotificationMessage alloc] initWithStatusMessage:responseString detailedMessage:responseString]];
}
My updated code using NSURLSessionTask:
#implementation RecorderManager
- (void)sendRequestToURL:(NSString*)url withData:(NSData*)postData forScreen:(NSString *)inScreenName
{
RecorderAsynchSubmit* delegate = [[RecorderAsynchSubmit alloc] initWithScreenName:inScreenName andURL:url];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:delegate delegateQueue:nil];
NSURL *URL = [NSURL URLWithString:url];
NSURLSessionTask *task = [session dataTaskWithURL:URL];
[task resume];
}
#implementation RecorderAsynchSubmit
// Implementing NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
[httpResponse setLength:0];
httpResponseCode = [((NSHTTPURLResponse *) response) statusCode];
completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
[httpResponse appendData:data];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
if (error) {
// Handle error
} else {
NSString *responseString = [[[NSString alloc] initWithData:httpResponse encoding:NSUTF8StringEncoding] copy];
if (httpResponseCode == STATUS_CODE_VALID) {
responseString = #"Submit Succeeded";
} else {
responseString = [NSString stringWithFormat:#"Your entry could not be submitted. Data has been stored locally. Error Message: %#", responseString];
}
[[NSNotificationCenter defaultCenter]
postNotificationName:#"submissionCompleteEvent"
object:[[RecorderNotificationMessage alloc] initWithStatusMessage:responseString detailedMessage:responseString]];
}
}
The original code is working fine and returns the expected result, however the updated code always returns a 404 response from the server.

Objective C: SSL Pining

I have implement NSURLConnectionDataDelegate in my class and I have implemented the method:
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
But when I make new NSURLConnection this method isn't called. Why? Where is the problem? The connections is an SSL connection.
I have look inside an example project downloaded by internet (I don't remember where) and this project work fine, but if I do the some step in my project don't work. I need any external library or to set something in the proj? You can suggest me a for-dummies guide?
Edit 1:
In the example I use:
NSURL *httpsURL = [NSURL URLWithString:#"https://secure.skabber.com/json/"];
NSURLRequest *request2 = [NSURLRequest requestWithURL:httpsURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:15.0f];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request2 delegate:self];
[connection start];
But I want to work with any kind of NSURLConnection.
Edit 2:
This is my complete code:
#interface ConnectionDelegate : NSObject<NSURLConnectionDataDelegate>
#property (strong, nonatomic) NSURLConnection *connection;
#property (strong, nonatomic) NSMutableData *responseData;
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
-(void)testHTTPRequest;
#end
#implementation ConnectionDelegate
-(void)testHTTPRequest
{
NSURL *httpsURL = [NSURL URLWithString:#"https://secure.skabber.com/json/"];
NSURLRequest *request = [NSURLRequest requestWithURL:httpsURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:15.0f];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
[self.connection start];
if ([self isSSLPinning]) {
[self printMessage:#"Making pinned request"];
}
else {
[self printMessage:#"Making non-pinned request"];
}
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate));
NSData *skabberCertData = [self skabberCert];
if ([remoteCertificateData isEqualToData:skabberCertData] || [self isSSLPinning] == NO) {
if ([self isSSLPinning] || [remoteCertificateData isEqualToData:skabberCertData]) {
[self printMessage:#"The server's certificate is the valid secure.skabber.com certificate. Allowing the request."];
}
else {
[self printMessage:#"The server's certificate does not match secure.skabber.com. Continuing anyway."];
}
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}
else {
[self printMessage:#"The server's certificate does not match secure.skabber.com. Canceling the request."];
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (self.responseData == nil) {
self.responseData = [NSMutableData dataWithData:data];
}
else {
[self.responseData appendData:data];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *response = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
[self printMessage:response];
self.responseData = nil;
}
- (NSData *)skabberCert
{
NSString *cerPath = [[NSBundle mainBundle] pathForResource:#"secure.skabber.com" ofType:#"cer"];
return [NSData dataWithContentsOfFile:cerPath];
}
- (void)printMessage:(NSString *)message
{
Log(#"%#",message);
}
- (BOOL)isSSLPinning
{
NSString *envValue = [[[NSProcessInfo processInfo] environment] objectForKey:#"SSL_PINNING"];
return [envValue boolValue];
}
#end
If i put a breakpoint on connection:willSendRequestForAuthenticationChallenge: the program don't enter in it.

Video not getting downloaded

I need to download this video http://studiokicks.com/xtr/basic/1.mov The video is not getting downloaded when I use the following code:
NSURL *requestURL = [NSURL URLWithString:itemURL];
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
NSData *data = [NSData dataWithContentsOfURL:requestURL];
NSLog(#"data - %d",[data length]);
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"didReceiveResponse");
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ((([httpResponse statusCode]/100) == 2)) {
returnData = [NSMutableData data];
}
else
{
NSDictionary *userInfo = [NSDictionary dictionaryWithObject: NSLocalizedString(#"HTTP Error", #"Error message displayed when receving a connection error.")forKey:NSLocalizedDescriptionKey];
NSError *error = [NSError errorWithDomain:#"HTTP" code:[httpResponse statusCode] userInfo:userInfo];
NSLog(#"%#",error);
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[returnData appendData:data];
// Build an array from the dictionary for easy access to each entry
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection1
{
NSString *filePath = [VIDEOPATH stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.mov",videoName]];
BOOL success = [returnData writeToFile:filePath atomically:YES];
NSLog(#"successfully saved - %d",success);
}
You need to set a member self.data of type NSMutableData.
Before starting loading the NSURLConnection, initialize: self.data = [NSMutableData new].
In the connectionDidReceiveData method do: [self.data appendData:data].
And in the connectionDidFinishLoading you can view the data.

how can I use NSURLConnection Asynchronously?

I am using this code to load data to my App, can you tell me how can I make this asynchronously?
NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:requestString] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request2 delegate:self];
if (connection)
{
NSLog(#"NSURLConnection connection==true");
NSURLResponse *response;
NSError *err;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request2 returningResponse:&response error:&err];
self.news =[NSJSONSerialization JSONObjectWithData:responseData options:nil error:nil];
NSLog(#"responseData: %#", self.news);
}
else
{
NSLog(#"NSURLConnection connection==false");
};
I think you should be bothered reading the documentation. There's a sendAsynchronousRequest:queue:completionHandler: method.
Create the connection with initWithRequest:delegate:startImmediately:, set yourself as its delegate and implement the delegate methods.
Block code is your friend. I have created a class which does this for you
Objective-C Block code. Create this class here
Interface class
#import <Foundation/Foundation.h>
#import "WebCall.h"
#interface WebCall : NSObject
{
void(^webCallDidFinish)(NSString *response);
}
#property (nonatomic, retain) NSMutableData *responseData;
-(void)setWebCallDidFinish:(void (^)(NSString *))wcdf;
-(void)webServiceCall :(NSString *)sURL_p : (NSMutableArray *)valueList_p : (NSMutableArray *)keyList_p;
#end
Implementation class
#import "WebCall.h"
#import "AppDelegate.h"
#implementation WebCall
#synthesize responseData;
-(void)setWebCallDidFinish:(void (^)(NSString *))wcdf
{
webCallDidFinish = [wcdf copy];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
int responseStatusCode = [httpResponse statusCode];
NSLog(#"Response Code = %i", responseStatusCode);
if(responseStatusCode < 200 || responseStatusCode > 300)
{
webCallDidFinish(#"failure");
}
[responseData setLength:0];
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"WebCall Error: %#", error);
webCallDidFinish(#"failure");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *response = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
response = [response stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
webCallDidFinish(response);
}
-(void)webServiceCall :(NSString *)sURL_p : (NSMutableArray *)valueList_p : (NSMutableArray *)keyList_p
{
NSMutableString *sPost = [[NSMutableString alloc] init];
//If any variables need passed in - append them to the POST
//E.g. if keyList object is username and valueList object is adam will append like
//http://test.jsp?username=adam
if([valueList_p count] > 0)
{
for(int i = 0; i < [valueList_p count]; i++)
{
if(i == 0)
{
[sPost appendFormat:#"%#=%#", [valueList_p objectAtIndex:i],[keyList_p objectAtIndex:i]];
}
else
{
[sPost appendFormat:#"&%#=%#", [valueList_p objectAtIndex:i], [keyList_p objectAtIndex:i]];
}
}
}
NSData * postData = [sPost dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:NO];
NSString * postLength = [NSString stringWithFormat:#"%d",[postData length]];
NSURL * url = [NSURL URLWithString:sURL_p];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:postData];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (theConnection)
{
self.responseData = [NSMutableData data];
}
}
#end
Then you to make this web call, you call it like this
WebCall *webCall = [[WebCall alloc] init];
[webCall setWebCallDidFinish:^(NSString *response){
//This method is called as as soon as the web call is finished
NSString *trimmedString = [response stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if([trimmedString rangeOfString:#"failure"].location == NSNotFound)
{
//Successful web call
}
else
{
//If the webcall failed due to an error
}
}];
//Make web call here
[webCall webServiceCall:#"http://www.bbc.co.uk/" :nil :nil];
See the setWebCallDidFinish method, it will not be called until the webcall has finished.
Hope that helps!!
Here is some code which I am using in my app:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:yourURL]];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error) {
NSLog(#"Error loading data from %#. Error Userinfo: %#",yourURL, [error userInfo]);
} else {
NSDictionary *dataFromServer = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
contentAsString = [[[dataFromServer objectForKey:#"page"] objectForKey:#"content"] stripHtml];
completionHandler(contentAsString);
}];
fyi: stripHTML is a NSString Category to remove HTML tags from JSON --> Found it Here
you can call your content in your class like that:
[yourClass getDataWithcompletionHandler:^(NSString *content) {
yourObject.content = content;
[yourClass saveManagedObjectContext];
}];
if you implement it once, you won't want to use synchronous connection again...
Check this out: HTTPCachedController
It will help you send POST and GET requests, while it will cache the response and after that it will return the cached data when no internet connection is available.
HTTPCachedController *ctrl = [[[HTTPCachedController alloc] initWithRequestType:1 andDelegate:self] autorelease];
[ctrl getRequestToURL:#"https://api.github.com/orgs/twitter/repos?page=1&per_page=10"];
You will get notified when the data are fetched through a delegate method:
-(void)connectionFinishedWithData:(NSString*)data andRequestType:(int)reqType

JSON objects from URL connection displayed in tableview

#pragma mark -
#pragma mark Fetch loans from internet
-(void)loadData
{
self.responseData = [NSMutableData data];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:
#"http://192.168.1.104:8080/Test/ItemGroup.jsp"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connection release];
self.responseData = nil;
}
#pragma mark -
#pragma mark Process loan data
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
self.responseData = nil;
array=[responseString JSONValue];
NSMutableString *text=[NSMutableString stringWithString:#"Values:\n"];
for (int i=0; i <[array count]; i++) {
[text appendFormat:#"%#\n",[array objectAtIndex:i]];
// NSLog(#"Values:""%#\n",array);
}
}
You can use RestKit (a Cocoa RESTful web services framework) to fetch the data and use the object mapping feature to map returned data to an array of objects.
The example given in the RESTKit Object Mapping wiki maps a JSON doc into an array of Article instances: https://github.com/RestKit/RestKit/wiki/Object-mapping