in my Program, I have a NSMutableData variable that collect the information from http://www.nhara.org/scored_races-2013.htm. After about the third time it gets information from a website, when it contains 90810 bytes, it either disappears or becomes null because if I print it a NSString, it is null. Here is the code
- (void)viewWillAppear:(BOOL)animated
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc] initWithCapacity:180000];
[self fetchEntries];
[super viewWillAppear:animated];
}
- (void)fetchEntries
{
// Construct a URL that will ask the service for what you want
NSURL *url = [NSURL URLWithString: #"http://www.nhara.org/scored_races-2013.htm"];//
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always comes in the correct order
[xmlData appendData:data];
NSLog(#"%#",xmlData);
NSString *xmlCheck = [[[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding]autorelease];
NSLog(#"xmlCheck = %#", xmlCheck);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"error= %#",error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)conn {
// We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"xmlCheck2 = %#", xmlCheck);
}
What confuses me the most is that my NSMutableData stores data, but then loses it while claiming to have the same number of bytes.
Is there a constraint to the NSMutableData's size or is my problem just memory management?
You need to create a property for your xmlData variable. In your header file after your
#interface MyClass, make one like so
#property (nonatomic, retain) NSMutableData * xmlData;
If you are using ARC you leave it as strong if you using below ARC you change strong to retain. When you want to use your variable you do self.xmlData
Related
I've tried most of advises from stackoverflow but none of them was good for me.
My client wants to save user data in json with GET request in format:
http://website.com/users/save.php?save={"email":"user#domen.com","name":"Will Smith"}
I'm using objective-c
Please advise
Thanks
Edit
my php file looks like this:
<?php
$save = $_GET['save'];
$fp = fopen("save_users_ww.txt", "a+");
fputs($fp,$save."\r\n");
fclose($fp);
?>
so post don't work for me. Thank you for help again
In case someone else will need a solution, this is my code:
.h file:
#interface WelcomeViewController : UIViewController <NSURLConnectionDelegate>
{
NSMutableData *_responseData;
}
.m file:
-(void)postToDataBaseWithName:(NSString*)nameToPost andEmail:(NSString*)emailToPost {
NSString *str = [NSString stringWithFormat:#"http://website.com/users/save.php?save={\"email\":\"%#\",\"name\":\"%#\"}", emailToPost, nameToPost];
str = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:str];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(conn) {
}
}
also add delegate methods to see how it works:
#pragma mark NSURLConnection Delegate Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
NSLog(#"didReceiveResponse");
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data to the instance variable you declared
NSLog(#"didReceiveData");
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSLog(#"connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
// Check the error var
NSLog(#"didFailWithError = %#", error);
}
This question already has answers here:
didReceiveData is not getting all data
(2 answers)
Closed 7 years ago.
I retrieve NSData from a url, then I try set it to an image.
In the console it returns null, however when I request the data and set the image again, the image than loads?
Why do does this have to be done twice for it to load??
This is the two methods I use to get the picture.
-(void)getUserPicture {
//Grab and upload user profile picture
imageData = [[NSMutableData alloc] init]; // the image will be loaded in here
NSString *urlString = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture?type=large", userId];
NSMutableURLRequest *urlRequest =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:3];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest
delegate:self];
if (!urlConnection) NSLog(#"Failed to download picture");
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
userPicture = [UIImage imageWithData:data];
NSLog(#"%#",userPicture); //returns null in console first time, until reloaded???
}
The connection:didReceiveData: method is called repeatedly as the data is loaded incrementally. You probably want the connectionDidFinishLoading: method instead.
By the way, you'll still likely need a connection:didReceiveData:, but rather than trying to create the image, you'll just be appending the new data to a buffer. Then in the connectionDidFinishLoading: method, you take the buffer and create your image.
Example code, but please add error handling as needed:
#property (strong, nonatomic) NSMutableData *data;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.data = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
self.userPicture = [UIImage imageWithData:self.data];
}
I have tried to find a similar question but I was unable to do so. I have a singleton that is used to gather information through out my app. Once of the values is obtained within the following method.
-(NSString *)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data-(NSString *)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
In this method I get the response from th webservice that I am trying to connect to. Everything is good. However any attempt to save the variable value to my singleton fails. Within this method no problem. When I try to get to the next view and reference my singleton, it is as if the value never gets saved.
Here is a skeleton of my code.
NBXJSONResponse *jsonResponse = [NBXJSONResponse sharedHostedResponseSingleton];
[jsonResponse setHostedURL:_hostedURL];
Basically the goal here is to have the hosted payment page appear in the next view. The flow flow for that works. I just need to pass the URI link so that payment can be made.
I know that I can return a value from this delegate method, but since I never explicitly call this method, so I am unsure where it is being called. Probably the reason why my values are not being saved in the singleton class.
EDIT:
Right now I have one view which does all of the action.
//
// NBXViewController.h file
#import <UIKit/UIKit.h>
#interface NBXViewController : UIViewController
//*************************************************
// Variables to be declared for NBXViewController *
//*************************************************
#property (strong, nonatomic) IBOutlet UILabel *storeLabel;
#property (strong, nonatomic) IBOutlet UIButton *purchaseButton;
#property (strong, nonatomic) IBOutlet NSString *hostedURL;
//*************************************************
// Button Action methods for the buttons on View *
//*************************************************
- (IBAction)puchaseButtonAction:(id)sender;
//*************************************************
// Connection Delegate Methods *
//*************************************************
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; // Handle Connection Error
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; // Data Received from Connection (Header Information)
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; //Response from Connection (Return from Hosted being called)
-(void)connectionDidFinishLoading:(NSURLConnection *)connection; // Coonection did finish loading
#end
Implementation file.
//
// NBXViewController.m
// HostedAPI
//
// Created by Philip Teoli on 3/1/2014.
// Copyright (c) 2014 Philip Teoli. All rights reserved.
//
#import "NBXViewController.h"
#import "NBXJSONResponse.h"
#interface NBXViewController ()
#end
#implementation NBXViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//****************************************
// PurchaseButton Action Method *
//****************************************
- (IBAction)puchaseButtonAction:(id)sender
{
//************************************
// Building JSON Request *
//************************************
NSString *jsonString = #"Sample Request";
//**************************************
// Convert JSON String to NSData *
//**************************************
NSData* jsonRequestData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
//**************************************
// Creating JSON object to Send *
//**************************************
NSString *jsonRequest = [[NSString alloc] initWithData:jsonRequestData encoding:NSUTF8StringEncoding];
//*****************************************
// Base64 Encoding for Application Header *
//*****************************************
NSString *base64Signature = #"NbMIIkomZ8mFNw97EGRT:NAA5e965731e8a27ab11f5f";
NSString *basic = #"Basic: ";
NSData *base64SignatureData = [base64Signature dataUsingEncoding: NSUTF8StringEncoding];
NSString *base64SignatureEncoded = [base64SignatureData base64EncodedStringWithOptions:0];
NSString *header = nil;
header = [basic stringByAppendingString:base64SignatureEncoded];
// NSLog(#"Encoded Header: %#", header);
//*************************************
// Preparing to send XML through POST *
//*************************************
NSString *postLength = [NSString stringWithFormat:#"%lu", (unsigned long)[jsonRequest length]]; //Calculating the Content Length
NSData *postData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding]; // preapring JSON Request to be sent
//**************************************
// Headers and POST Body *
//**************************************
NSURL *serviceUrl = [NSURL URLWithString:#"https://pay.test.ewbservice.com/orders"];
NSMutableURLRequest *serviceRequest=[NSMutableURLRequest requestWithURL:serviceUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
[serviceRequest setValue:postLength forHTTPHeaderField:#"Content-Length"];
[serviceRequest setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[serviceRequest setValue:header forHTTPHeaderField:#"Authorization"];
[serviceRequest setHTTPMethod:#"POST"];
[serviceRequest setHTTPBody:postData];
NSURLConnection *connection = [[NSURLConnection alloc]
initWithRequest:serviceRequest
delegate:self startImmediately:YES];
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[connection start];
NSLog(#"Hosted URL in Button: %#", _hostedURL);
}
//****************************************************
// Implementation of Connection Delegate Methods *
//****************************************************
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"did fail");
}
//*******************************************************
// Connection Data Received *
//*******************************************************
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSString *dataResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSError *error = nil;
NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData: [dataResponse dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
//********************************
// Iterating through Dictionary *
//********************************
NSArray *jsonLink = nil;
for(id key in jsonDictionary)
{
if ([key isEqualToString:#"link"])
{
jsonLink = [jsonDictionary objectForKey:key]; // this returns a dictionary. Will need to parse dictionary another 2 times to get proper URI.
}
}
NSDictionary *test = [jsonLink objectAtIndex:0];
for(id key in test)
{
if ([key isEqualToString:#"uri"])
{
_hostedURL = [test objectForKey:key];
}
}
NBXJSONResponse *jsonResponse = [NBXJSONResponse sharedHostedResponseSingleton];
[jsonResponse setHostedURL:_hostedURL];
}
//*******************************************************
// Connection Response Method *
//*******************************************************
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"did receive response: \n %#", response);
NBXJSONResponse *jsonResponse = [NBXJSONResponse sharedHostedResponseSingleton];
[jsonResponse setHostedURL:_hostedURL];
}
//*******************************************************
// Connection Finished Loading Data Method *
//*******************************************************
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"did finish loading!!! \n%#", _hostedURL);
// NBXJSONResponse *jsonResponse = [NBXJSONResponse sharedHostedResponseSingleton];
// [jsonResponse setHostedURL:_hostedURL];
}
#end
Please let me know of your thoughts. I can post more details if needed. Thanks in advance for your help!!!
Regards,
Thanks to the great help from #rdelmar I was able to get through this. Basically in short what was happening was that I was going to the next view before the information was received by my previous view from the web service. So when I was trying to change a label with a value to my Singleton, it was not stored yet. How I got around the issue is that when I click a button I wait until the web services responses and then I add a view to go to the new view. Now my URL that I was waiting reaches me, I save it to Singleton and then I go to the next view.
I will add my code once I can grab it and post it.
Thanks again for all of your help Eric!!! Your patience and help make you a great person on this community.
Regards,
Corporate One
I have an app where there are five screens.
On each screen, in viewDidLoad I am accessing data from server.
On each screen I have next button.
When I go from screen one to screen five (by clicking Next 4 times), in NSLog, I still see the process done by all previous four view controller.
Is there any way, how can I kill those threads?
In short, I don't want to do any process when I go away from that view i.e. if I go from view 3 to 4, I want to stop the task that I was for view 3.
Getting data of earlier views & waiting for that data (which is unwanted) is not good for app, hence I want like what I explained above.
Edit 1
Below is the code I use for reading the data.
.h
#property(nonatomic, retain) NSMutableData *webData;
#property(nonatomic, retain) NSMutableData *data;
Using below I request the data
.m
NSString *myTMainURL = [NSString stringWithFormat:#"http://www.google.com"];
NSURL *url = [NSURL URLWithString:myTMainURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
For reading, below is how I read.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"didReceiveResponse");
data = [[NSMutableData alloc] init ];
[webData setLength: 0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData {
NSLog(#"didReceiveData");
[data appendData:theData];
[webData appendData:data];
NSLog(#"didreceveidata leng===%d===%d", [webData length], [data length]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"connectionDidFinishLoading");
NSString *myDataFromLink = [[NSString alloc] initWithBytes: [data mutableBytes] length:[data length] encoding:NSUTF8StringEncoding];
NSLog(#"myDataFromLink====%#--", myDataFromLink);
}
In viewWillDisappear:, send cancel to whatever operation is running.
This, of course, assumes you have a cancelable task/method/operation.
For example, for network requests, if you use NSURLConnection this is the case when you employ the delegate approach. With NSURLConnection's convenient class method sendAsynchronousRequest:queue:completionHandler: this is not possible. Thus, any serious application would use the delegate approach, since a long running asynchronous operation must be cancelable.
You can use NSOperation and cancel the operation when you go to the next view may be in the action of the next button or just in viewWillDisappear: method
Edit
Since You are using NSURLConnection then you can call cancel on the connection in viewWillDisappear:
.h
#property(nonatomic, retain) NSMutableData *webData;
#property(nonatomic, retain) NSMutableData *data;
#property(nonatomic, retain) NSURLConnection *connection;
.m
NSString *myTMainURL = [NSString stringWithFormat:#"http://www.google.com"];
NSURL *url = [NSURL URLWithString:myTMainURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
in viewWillDisappear:
[self.connection cancel]
Since you are using NSURLConnection, You can cancel that connection and stop the NSURLRequest which you are using with your NSURLConnection with following code:
-(void)viewDidDisappear
{
[super viewDidDisappear];
[connection cancel]; // Here connection is your NSURLConnection object.
}
I'm trying to get XML from a page, but the NSURLConnection is not returning anything.
- (void)downloadDataWithMission:(NSString *)mission
{
// Create a new data container for the stuff that comes back from the service
xmlData = [[NSMutableData alloc] init];
// Construct a URL that will ask the service for what you want
NSString *urlstring = [NSString stringWithFormat:#"http://www.google.com/"];
// , mission, [self getCountry]
NSURL *url = [NSURL URLWithString:urlstring];
// Put that URL into an NSURLRequest
NSURLRequest *req = [NSURLRequest requestWithURL:url];
// Create a connection that will exchange this request for data from the URL
urlConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];
}
# pragma mark NSURLConnection
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere
[xmlData setLength:0];
}
// This method will be called several times as the data arrives
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Add the incoming chunk of data to the container we are keeping
// The data always come in the correct order
[xmlData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// We are just checking to make sure we are getting the XML
NSString *xmlCheck = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
NSLog(#"xmlCheck = %#", xmlCheck);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Release the connection object, we're done with it
urlConnection = nil;
// Release the xmlData object, we're done with it
xmlData = nil;
// Grab the description of the error object passed to us
NSString *errorString = [NSString stringWithFormat:#"Connection Failed: %#", [error localizedDescription]];
// Create and show an alreat view with this error displayed
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error" message:errorString delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}
#end
Why is the connection not working? Is this a problem in the delegate? In another project, all worked fine. The base SDK was the same in those projects - iOS 6.1.
Everything up to this line works perfectly:
NSString *xmlCheck = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
However it does not handle the encoding I think. Maybe there is sone invalid UTF-8 char at google. Try NSASCIIStringEncoding instead and it will work. If you want to use UTF-8 you might need to dig into why google is not UTF-8 compliant.