My game needs to fill tableView cells with a bunch of things from my server database. This has been working fine. Then I upgraded Xcode to 4.6 and targeted iOS6.1, to please the App Review Team folks. Now, one of my connections never completes. (All of the other Posts seem to work correctly, as always.) Here's my post:
- (void) fillCells {
Cell_QtoA *newCell = [[Cell_QtoA alloc] initCellUser:usrID Grp:grpID Qtn:0 Gnm:#"na" Cat:#"na" Sit:#"na" Pfl:#"na" Lks:0 isA:0 ddA:0 ];
NSMutableURLRequest *reqPost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kFillCells] andDataDictionary:[newCell toDictC]];
(void) [[NSURLConnection alloc] initWithRequest:reqPost delegate:self];
}
I think it's working fine. The PHP and database haven't changed. Everything worked great yesterday, before the upgrades. Here's my connection method:
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"data = %#", data);
NSString *error;
NSArray *array = (NSArray *)[NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:0 errorDescription:&error];
if( error ) {
NSLog(#"Error = %#", error);
return;
}
NSLog(#"1st object in array of %d is %#", [array count], array );
}
Because I suspected net speeds to be an issue, I added a timer to the call, which I never needed before:
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(fillCells) userInfo:nil repeats:YES];
The timer didn't help. Still get errors:
"Unexpected EOF" and "Unexpected character z (or whatever) at Line 1"
The NSLog of data shows hex data that appears cut off, like:
<3c3f786d 6c207665 ... 63743e0a 3c2f6172 7261793e 0a3c2f70 6c697374 3e>
It's like the reception is being interrupted. Anyone know what's happening here? Thanks!
You aren't using all the response data; as mention in the NSURLConnectionDelegate reference:
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 you need to create an NSData instance variable; clear before the request and append to it whenever new data arrives. Then use the didFinishLoading delegate method to trigger the call to propertyListFromData with the complete response.
Related
Hi My problem is that i am getting a response from a web service and when i parse it and add to table and reload the table view it is not refreshing . Although if i call the [table reload] in keyboard is shown it gets updated there. Could someone tell me if im missing anything
This is what i am trying to do
- (void) longPoll {
//create an autorelease pool for the thread
#autoreleasepool {
NSLog(#"polling");
VSAppDelegate *var = (VSAppDelegate*)[[UIApplication sharedApplication] delegate];
//compose the request
NSError* error = nil;
NSHTTPURLResponse* response = nil;
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"polling response is %d",response.statusCode);
//pass the response on to the handler (can also check for errors here, if you want)
[self performSelectorOnMainThread:#selector(dataReceived:) withObject:responseData waitUntilDone:YES];
}
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) startPoll {
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData
{
//process the response here
NSError *error = nil;
NSLog(#"polling data is %#",[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding]);
NSLog(#"polling data is %#",[[theData base64EncodedString]base64DecodedString]);
NSDictionary *notifDic= [NSJSONSerialization JSONObjectWithData:theData options:kNilOptions error:&error];
//VSViewControllerSplit *split = [[VSViewControllerSplit alloc]init];
[self RecieveFunction:notifDic];
}
try it
dispatch_async(dispatch_get_main_queue(), ^{
[tablrView reloaddata];
});
The dataReceived method doesn't appear to be calling reloadData. I'll assume that RecieveFunction method does, though, but you should confirm that. It's hard to say without seeing RecieveFunction.
The more fundamental issue would appear to be that dataReceived method is creating a new instance of VSViewControllerSplit, calling its RecieveFunction method, and then letting this new VSViewControllerSplit instance fall out of scope (and if using ARC, get deallocated unless you pushed to it, presented it, etc.). You presumably don't want to create a new VSViewControllerSplit every time longPoll calls dataReceived, but rather just reference the existing instance.
hi I have an UITableView. It loads numberof data from a web service. What I want to load this tableview 10 by 10.Initially it loads first 10 items. When user scroll to the end of the UITableView it should load next 10 of records from the server. so in my scrollviewDidEndDeclarating delegate I put like this
`
if (scrollView.tag==24) {
[self performSelector:#selector(loadingalbumsongs:) withObject:nil afterDelay:0.1];
}`
but the problem is when I stop the scroll it is getting stuck untill load the table view. Can anybody give me a solution for this
Thanks
Try NSURLCONNECTION that will help you to call asynchronous webservice
A NSURLConnection object is used to perform the execution of a web service using HTTP.
When using NSURLConnection, requests are made in asynchronous form. This mean that you don't wait the end of the request to continue,
This delegate must have to implement the following methods :
connection:didReceiveResponse : called after the connection is made successfully and before receiving any data. Can be called more than one time in case of redirection.
connection:didReceiveData : called for each bloc of data.
connectionDidFinishLoading : called only one time upon the completion of the request, if no error.
connection:didFailWithError : called on error.
EXAMPLE: -
NSData *data = [[NSMutableData alloc] init];
NSURL *url_string = [NSURL URLWithString:
#"Your URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url_string];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (!conn) {
// this is better if you #throw an exception here
NSLog(#"error while starting the connection");
[data release];
}
for each block of raw data received you can append your data here in this method :
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)someData {
[data appendData:someData];
}
connectionDidFinishLoading will call at the end of successfully data receivied
use this code for load more action
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//scrollView.contentSize.height-scrollView.frame.size.height indicates UItableView scrool end
if (scrollView.contentOffset.y >= scrollView.contentSize.height-scrollView.frame.size.height)
{
if(loadMore)
{
loadmore=no;
//call your Web service
}
}
}
I wish to fetch data for an array of URLs that return JSON data. I am trying the following code:
for (int i =0; i<numberOfDays; i++)
{
NSData *data = [NSData dataWithContentsOfURL:[wordURLs objectAtIndex:i]];
NSLog(#"%#",[wordURLs objectAtIndex: i]);
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
}
'wordURLs' are the array of URLs and in my 'fetchedData:' method, I save the returned JSON data to a plist file.
The issue is that for all number of times that the loop runs, the data is returned for only one/two particular URLs (i.e. say for the urls at indices at 1 and 3, or 1 and 2 etc). I log and see that the URLs are different for each time the 'data' variable is initialized.
What is a better way of doing this?
I have used NSJSONSerialization for parsing JSON.
There are much better ways of doing this. The problem with what you are trying to do is that it is synchronous, which means your app will have to wait for this action to be completed before it can do anything else. I definitely would recommend looking into making this into an asynchronous call by simply using NSURLConnection and NSURLRequests, and setting up delegates for them.
They are relatively simple to set up and manage and will make your app run a million times smoother.
I will post some sample code to do this a little later once I get home.
UPDATE
First, your class that is calling these connections will need to be a delegate for the connections in the interface file, so something like this.
ViewController.h
#interface ViewController: UIViewController <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
NSMutableData *pageData;
NSURLConnection *pageConnection;
}
Then you will need to create/initialize the necessary variables in you implementation
ViewController.m
-(void) viewDidLoad {
pageData = [[NSMutableData alloc] init];
NSURLRequest *pageRequest= [[NSURLRequest alloc] initWithURL:pageURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:4];
pageConnection = [[NSURLConnection alloc] initWithRequest:pageRequestdelegate:self];
}
Then you also need the delegate functions that will get called as the data is retrieved.
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (connection == pageConnection) {
[pageData appendData:data];
}
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == pageConnection) {
// Do whatever you need to do with the data
}
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (connection == pageConnection) {
// Do something since the connection failed
}
}
Of course this example only includes one URL being loaded, but you could make it as many as you want. You will of course have to keep track of all of the necessary NSURLConnections so you know where to put the data you received, as well as what actions to take in case of a failure or the connection being completed successfully, but that is not a hard extension from what I have given.
If you see any glaring errors or something does not work, please let me know.
i am establishing a UDP connection using GCDAsyncSocket(ios device). Everything working fine and im able to send and receive messages, my problem is that i want to exchange data fast. I can send pretty fast data from my iphone to a pc but i cant get at that speed data from pc, more specific i want to be able to get data every 100ms.
I use this function when i connect successfully:
-(void)startRead {
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(startRead) userInfo:nil repeats:YES];
[asyncSocket readDataWithTimeout:-1 tag:0];
}
With this i can read data with 1sec interval but if i try to put 0.1 seconds my program freezes.(Same with values under 1second) Im sure that im doing something wrong here and there will be a way to achieve what i want so if anybody know plz help!!
thanx
I believe the above comment is correct, you've not set the Delegate correctly on init. The socket creation should be something like this
GCDAsyncUdpSocket* udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *error = nil;
if (![udpSocket bindToPort:0 error:&error])
{
[self logError:[NSString stringWithFormat:#"Error binding: %#", error]];
return;
}
if (![udpSocket beginReceiving:&error])
{
[self logError:[NSString stringWithFormat:#"Error receiving: %#", error]];
return;
}
NSString *_host = nil;
uint16_t _port = 0;
[GCDAsyncUdpSocket getHost:&_host port:&_port fromAddress:udpSocket.localAddress];
[self logInfo:[NSString stringWithFormat:#"Socket setup on host %#:%d", _host, _port]];
[self logInfo:#"Socket created successfully."];
Unless you're using a different version of GCDAsyncUdpSocket than I'm familiar with, the correct callback method is actually the below method. This is called automatically when the delegate is set and a packet is received on the correct port.
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
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.