In my iPAD application, I have 6 UITableViews. To get data for each of the tableview, I call a Webservice using NSURLConnection and parse the xml I get back from the Webservice and store data into the database.
Since I have 6 UITableView, I send the Webservice request for each of the views at the same time. However, the problem that I am facing is that, for my app to receive data from the Webservice on the -(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data for 1 table view keeps depending upon the database operations performed by the parsers of the other tableviews.
For example, the webservice request for tableview's A, B, C, D are all sent at the same time. if I get back the data on the -(void) connection:(NSURLConnection *) connection didReceiveData:(NSData *) data function, until the xml received is parsed and saved to my database, I am not getting the response back for the other tableviews.
I am unable to figure out what I am doing wrong. I know NSURLConnection is asynchronous but the response I am getting does not seem so.
Here is my code -
For sending the Webservice request -
- (void) callMedicationWebService
{
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn)
{
webData = [[NSMutableData data] retain];
}
}
-(void) connection:(NSURLConnection *) connection
didReceiveResponse:(NSURLResponse *) response
{
[webData setLength: 0];
}
-(void) connection:(NSURLConnection *) connection
didReceiveData:(NSData *) data
{
[webData appendData:data];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm:ss"];
NSString *alertMessage = [formatter stringFromDate:[NSDate date]];
[formatter release];
NSLog(#"got data back from WS %#", alertMessage);
}
-(void) connectionDidFinishLoading:(NSURLConnection *) connection
{
[connection release];
// Parse xml
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:[CommonHelper decodeHTMLCharactorsFromString:webData]];
TableAHandler *handler = [[TableAHandler alloc] init];
[handler initTableAHandler];
[xmlParser setDelegate:handler];
[xmlParser setShouldResolveExternalEntities:YES];
[xmlParser setShouldProcessNamespaces:YES];
BOOL success = [xmlParser parse];
}
Would someone be able to help me what I am doing wrong?
Asynchronous doesn't necessarily mean that the callback function itself is called in a separate thread.
if you want all the parsing processes to happen at the same time you're gonna have to move the parsing processes to separate threads.
although the better solution would be not to use 5 different URLRequests, and to use only one that returns all the required information.
Related
This is first time I am trying.
Till now I am successful in getting DATA from SERVER in JSON format.
Now what I want to do is,
I have two NSString values that I have to send to server and server will check for them.
I don't know what checking mechanism is behind.
I am just sending two strings and server will return me try or false.
And I have to show that true or false thing.
All this will be called onClick of UIButton
Here what I tried,
NSString *str = [NSString stringWithFormat:#"http://XXXXXXXXXXXXXXXXXXXXXXX/api/CaptchaImage/CheckCaptchValid?validstring={%#}&encodestring={%#}",string1,string2];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] init];
[req setURL:[NSURL URLWithString:str]];
NSURLConnection *connGet = [[NSURLConnection alloc]initWithRequest:req delegate:self];
if(connGet)
{
NSLog(#"Connected successfully");
}
else
{
NSLog(#"Not connected successfully");
}
It gives me NSLog as connected successfully,
But I am struck here,
I want a response from server too in NSString format, either True or False.
Can any one guide me for further steps.
I tried some SO links, but didn't get much.
Thanks in advance.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[myData appendData:data];
}
-(void)connectionDidFinishLoading: (NSURLConnection *)connection {
response = [[NSString alloc] initWithData:myData encoding:NSUTF8StringEncoding];
}
Try this, but I have not tested this code. add appropriate delegate method.
Hope this will work for you
I'm trying to get data from a website to display it inside a table view
My code:
-(void)loadTutorials {
NSURL *url = [NSURL URLWithString:[#"http://www.example.com/search?q=" stringByAppendingString:self.searchString]];
NSURLRequest *UrlString = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:UrlString
delegate:self];
[connection start];
NSLog(#"Started");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
TFHpple *tutorialsParser = [TFHpple hppleWithHTMLData:data];
NSString *tutorialsXpathQueryString = #"//div[#id='header']/div[#class='window']/div[#class='item']/div[#class='title']/a";
NSArray *tutorialsNodes = [tutorialsParser searchWithXPathQuery:tutorialsXpathQueryString];
NSMutableArray *newTutorials = [[NSMutableArray alloc] init];
for (TFHppleElement *element in tutorialsNodes) {
Data *tutorial = [[Data alloc] initWithTitle: [[element firstChild] content]
Url: [#"http://www.example.com" stringByAppendingString: [element objectForKey:#"href"]]
];
[newTutorials addObject:tutorial];
}
_objects = newTutorials;
[self.tableView reloadData];
}
but the data is not showing up, is the data not finished loading?
I got it to working without NSURLConnection but then it will stop the program until the data is recieved
According to NSURLConnectionDataDelegate
connection:didReceiveData:
is called in a incrementally manner.
The newly available data. The delegate should concatenate the contents
of each data object delivered to build up the complete data for a URL
load.
So this means you should append new data within this method.
Then, in
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
you should manipulate your data.
So, for example
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// Create space for containing incoming data
// This method may be called more than once if you're getting a multi-part mime
// message and will be called once there's enough date to create the response object
// Hence do a check if _responseData already there
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Append the new data
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Parse the stuff in your instance variable now
}
Obviously you should also implement the delegate responsible for error handling.
A simple note is the following. If data is too big and you need to do some computations stuff (e.g. parsing), you could block the UI. So, you could move the parsing in a different thread (GCD is your friend). Then when finished you could reload the table in the main thread.
Take a look also here for further info: NSURLConnectionDataDelegate order of functions.
My app goes to a viewcontroller, makes two automatic server requests, makes the connection, retrieves the data and correctly displays it, and is done. The user clicks a "likes" button and two more server requests are made - successfully. Displays are correct. Should be done. Then it crashes, with the error:
[__NSCFNumber isEqualToString:]: unrecognized selector sent to instance
I'm using the very handy SimplePost class (by Nicolas Goles). Here are my requests, which are both called in viewDidLoad:
- (void) setScore {
Profile *newPf = [[Profile alloc] initID:thisUser profil:#"na" scor:score];
NSMutableURLRequest *reqPost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kMyProfileURL] andDataDictionary:[newPf toDictPf]];
(void) [[NSURLConnection alloc] initWithRequest:reqPost delegate:self];
}
- (void) saveHist {
History *newH = [[History alloc] initHistID:thisUser hQid:thisQstn hPts:score hLiked:NO];
NSMutableURLRequest *reqHpost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kMyHistURL] andDataDictionary:[newH toDictH]];
(void) [[NSURLConnection alloc] initWithRequest:reqHpost delegate:self];
}
The only "new" thing with my custom classes (Profile and History) is the BOOL for hLiked, but it's "working" - the database is updating correctly.
Then, the user can click a "Likes" button (+ or -). Here are the other requests:
- (IBAction)likeClick:(id)sender {
double stepperValue = _likeStepper.value;
_likesLbl.text = [NSString stringWithFormat:#"%.f", stepperValue];
[self updateLikes];
[self updateHist];
}
- (void) updateLikes {
// update the question with the new "liked" score
NSInteger likesN = [_likesLbl.text integerValue];
Questn *qInfo = [[Questn alloc] initQwID:thisQstn askID:0 wCat:#"na" wSit:#"na" wAns1:#"na" wPts1:0 wAns2:#"na" wPts2:0 wAns3:#"na" wPts3:0 wAns4:#"na" wPts4:0 wJust:#"na" wLikes:likesN ];
NSMutableURLRequest *reqPost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kLikesURL] andDataDictionary:[qInfo toDictQ]];
(void) [[NSURLConnection alloc] initWithRequest:reqPost delegate:self];
}
- (void) updateHist {
History *newH = [[History alloc] initHistID:thisUser hQid:thisQstn hPts:98989 hLiked:YES];
NSMutableURLRequest *reqHpost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kHistURL] andDataDictionary:[newH toDictH]];
(void) [[NSURLConnection alloc] initWithRequest:reqHpost delegate:self];
}
Messy, right? Here's my connection code:
// connection to URL finished with Plist-formatted user data array returned from PHP
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSDictionary *array = (NSDictionary *)[NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:0 errorDescription:nil];
BOOL keyLikeExists = [array objectForKey:#"likes"] != nil;
if( keyLikeExists ) {
_likesLbl.text = [array objectForKey:#"likes"];
}
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Connection did fail." );
}
It all does a good job, and then a couple of seconds later it crashes with that "unrecognized selector" error mentioned above, like there's still some URL activity happening. There shouldn't be.
Anybody seen this kind of thing before? Many thanks for any help!
Somewhere in your code there's a call to the method isEqualToString:. The thing that's being sent that message is a NSNumber object rather than a string. Either there's a logic problem concerning the object type or there's a memory problem where a string was over-released and its memory is being re-used to hold a number.
Without seeing the context for the call, it's hard to guess.
If you break on the exception, the stack trace should tell you where in the code it's failing.
Short version of the question:
What is wrong with the following Kiwi/iOS mock expectation?
[[mockDelegate should] receive:#selector(connectionDidSucceedWithText:andStatus:) withArguments:[testString1 stringByAppendingString:testString2],theValue(value),nil];
Long version of question:
I am trying to write a test in Kiwi, iOS for a simple class that handles a NSConnection. To test that the class handles the callback from the NSConnection I send it the delegate methods NSConnection normally does. I have a delegate in the class that sends data back to whoever uses my class. To test my class I have to inject a mocked delegate and then check that my desired methods are called. Simple as that :)
My code for the Kiwi test is:
//Some ivars declared elsewhere:
testString1 = #"asd323/4 d14";
testString2 = #"as98 /2y9h3fdd14";
testData1 = [testString1 dataUsingEncoding:NSUTF8StringEncoding];
testData2 = [testString2 dataUsingEncoding:NSUTF8StringEncoding];
mockURLRespons = [NSHTTPURLResponse mock];
int value = 11111;
id mockDelegate = [KWMock mockForProtocol:#protocol(SharepointConnectionDelegate)];
communicator = [[SharepointCommunicator alloc] init];
it (#"should send recieve data back to delegate2", ^{
[communicator setDelegate:mockDelegate];
[mockURLRespons stub:#selector(statusCode) andReturn:theValue(value)];
[(id)communicator connection:niceMockConnector didReceiveResponse:mockURLRespons];
[(id)communicator connection:niceMockConnector didReceiveData:testData1];
[(id)communicator connection:niceMockConnector didReceiveData:testData2];
[(id)communicator connectionDidFinishLoading:niceMockConnector];
[[mockDelegate should] receive:#selector(connectionDidSucceedWithText:andStatus:) withArguments:[testString1 stringByAppendingString:testString2],theValue(value),nil];
});
And in my SharepointCommunicator.m:
-(void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSURLResponse *)response {
if (connection != aConnection) {
[connection cancel];
connection = aConnection;
}
responseData = [[NSMutableData alloc] init];
statusCode = [(NSHTTPURLResponse*)response statusCode];
}
-(void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)data {
if (aConnection != self.connection)
return;
[responseData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *txt = [[NSString alloc] initWithData:responseData encoding: NSASCIIStringEncoding];
NSLog(#"Statuscode: %i", statusCode);
NSLog(#"Data is: %#",txt);
[delegate connectionDidSucceedWithText:txt andStatus:statusCode];
[self.connection cancel];
self.connection = nil;
}
This code works and is correct. Debugging it with checkpoint shows it does as expected. The values of statusCode is 11111. and txt is testString1+textString2. Still it fails on the last row on in the test with the following error:
error: -[kiwiSharepointCommunicatorTest Sharepointcommunicator_AStateTheComponentIsIn_ShouldSendRecieveDataBackToDelegate2] : 'Sharepointcommunicator, a state the component is in, should send recieve data back to delegate2' [FAILED], mock received unexpected message -connectionDidSucceedWithText:"asd323/4 d14as98 /2y9h3fdd14" andStatus:11111
Test Case '-[kiwiSharepointCommunicatorTest Sharepointcommunicator_AStateTheComponentIsIn_ShouldSendRecieveDataBackToDelegate2]' failed (3.684 seconds).
Removing the last row in the test still generate the same error. I guess my understanding of receive:withArguments: is wrong..
You have to call [[mockDelegate should] receive... before the call to connectionDidFinishLoading to prepare the mockDelegate for the message it's about to receive.
I would like to know how I can stop/abort a NSURLConnection while it is performing it load request.
The reason I would like to know is that, I am parsing an XML using NSURLConnection and sometimes the time taken to get a response is too long.
here is my code to make things clearer...
I am parsing an XML using NSXMLParser and loading the req with my soap message before I request it using NSURLConnection
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if (conn)
{
webData = [[NSMutableData data] retain];
}
}
The following piece of code is what is standard
-(void) connection:(NSURLConnection *) connection
didReceiveResponse:(NSURLResponse *) response
{
[webData setLength: 0];
}
-(void) connection:(NSURLConnection *) connection
didReceiveData:(NSData *) data
{
[webData appendData:data];
}
In this, sometimes the time taken for the program to get to connection didReceiveData is too long and the user would need to abort that operation.
So I would like to know if this is possible.
I know how to abort after it starts parsing by using [parser abort] but I dont know how to abort the NSURLConnection.
It would be great if someone could help me out with this.
Use [conn cancel]; to stop an ongoing download.