Crashing after view controller URL request and connection finish correctly - ios

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.

Related

Send parameter to server and get return value in NSString format

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

NSOperationQueue does not cancel (remove) operations

I'm looking for a means to handle separate but related NSURLRequest and thought that I could add them to an NSOperationQueue and then manage them (run the request or not based on http status code - if the status code is 200 they can run, if not, stop all of them as the url string needs to be appended).
In my test code below I suspend the OQ to stop the processing of NSURLRequest (represented here by some public RSS feeds) but continue to the request to the OQ. I get the right number of operations (4). After adding all request to the OQ I then check to see if it has been suspended and if so, cancel all the operations.That works, at least the check if it has been suspended.
When I do a count check after canceling the operations I still get 4 but was expecting less (and hoping for 0). I'm using NSURLConnection to get the rss data in a NSObject subclass.
I understand from the docs that NSOQ will not remove an operation until it has reported that it is finished. (Is there a way to see this report?)
You cannot directly remove an operation from a queue after it has been added. An operation remains in its queue until it reports that it is finished with its task. Finishing its task does not necessarily mean that the operation performed that task to completion. An operation can also be canceled. Canceling an operation object leaves the object in the queue but notifies the object that it should abort its task as quickly as possible.
NSURLConnection doesn't have a willStart or similar delegate method so I can't track that but my feeling is the second RSS feed is in some sort of start process and that would explain why it is still in there. But I log the connectionDidFinishLoading delegate and so the first task is completed, so I was expecting at least that to be gone.
So my question is twofold.
1. If I nil out NSOQ, does that eliminate the operations within it? And what danger is there if one of those operations is in process - crash, hanging the app, etc?
2. Is there a way to cancel a NSURLConnection that is in process? (Assuming that the answer to 1 is yes, you are in the danger zone).
Here's my code:
- (void)viewDidLoad {
[super viewDidLoad];
connectionManager* myConnectionManager = [[connectionManager alloc] init];
NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
NSMutableArray* arrAddedOperations = [[NSMutableArray alloc] init];
NSArray* arrFeeds = [[NSArray alloc] initWithObjects:#"http://rss.cnn.com/rss/cnn_topstories.rss", #"http://hosted.ap.org/lineups/USHEADS-rss_2.0.xml?SITE=RANDOM&SECTION=HOME", #"http://feeds.reuters.com/reuters/topNews", #"http://newsrss.bbc.co.uk/rss/newsonline_world_edition/americas/rss.xml", nil];
//add operations to operation queue
for(int i=0; i<arrFeeds.count; i++) {
NSInvocationOperation* rssOperation = [[NSInvocationOperation alloc]
initWithTarget: myConnectionManager
selector:#selector(runConnection:)
object:[arrFeeds objectAtIndex:i]];
//check to put a suspension on the OQ
if (i>1) {
operationQueue.suspended = YES;
}
[operationQueue addOperation:rssOperation];
[arrAddedOperations addObject:[arrFeeds objectAtIndex:i]];
//incremental count to see operations being added to the queue - should be 4
NSLog(#"This is the number of operations added to the queue:%i", [operationQueue operationCount]);
}
if (operationQueue.suspended) {
//restart the OQ so we can cancel all the operations
operationQueue.suspended = NO;
//kill all the operations
[operationQueue cancelAllOperations];
//count to see how many operations are left
NSLog(#"OQ has been suspended and operations canclled. The operation count should be 0\nThe operation count is %i", [operationQueue operationCount]);
}
}
from NSURLConnection class
- (void) runConnection : (NSString*) strURL {
NSURLRequest* urlRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:strURL]];
self.myConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self startImmediately:NO];
[self.myConnection setDelegateQueue:self.myQueue];
[self.myConnection start];
self.myConnection = nil;
}
#pragma mark - NSURLConnection Delegates
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"%#", error.localizedDescription);
}
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"%#", [NSNumber numberWithInteger:httpResponse.statusCode]);
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
self.strReponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//NSLog(#"%#", self.strReponse);
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"task finished");
NSDictionary* dictUserInfo = [[NSDictionary alloc] initWithObjectsAndKeys:
#"Display Data", #"Action",
self.strReponse, #"Data",
nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"avc" object:self userInfo:dictUserInfo];
}
Edit: I don't need to save these operations as I am storing the incoming request in a mutable array and which just create a new OQ once they have been appended. I just want to make sure they are cancelled and not leaving the app in a fragile state.

NSURLConnection didReceiveData not loading data

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.

Bad URL on iPhone, when i type it in browser it works

I am making an jsonstring. When i execute it, it works when i do it in my browser. I do this by logging the exact url and copy it in the browser. Than i get the HTTP Get that i want, but in the iPhone i only get a Bad Login.
- (IBAction)getDown:(id)sender { //perform get request
NSLog(#"beginnen met versturen");
//NSString * _barCode = [[NSUserDefaults standardUserDefaults] objectForKey:#"phoneNumber"];
//build up the request that is to be sent to the server
//NSString*jsonString = [[NSString alloc] initWithFormat:#"{\"barcode\":\"%#\"}", _barCode];
NSString*jsonString = [[NSString alloc] initWithFormat:#"{\"barcode\":\"123456\"}"];
NSString *str = [NSString stringWithFormat: #"http://server.nl/scan.php?data=%#",jsonString];
NSLog(#"%#", str);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:str]];
NSLog(#"url: %#", request);
[request setHTTPMethod:#"GET"];
// [request addValue:#"getValues" forHTTPHeaderField:#"METHOD"]; //selects what task the server will perform
NSLog(#"met value: %#", request);
//initialize an NSURLConnection with the request
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(!connection){
NSLog(#"Connection Failed");
}
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ // executed when the connection receives data
receivedData = data;
/* NOTE: if you are working with large data , it may be better to set recievedData as NSMutableData
and use [receivedData append:Data] here, in this event you should also set recievedData to nil
when you are done working with it or any new data received could end up just appending to the
last message received*/
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ //executed when the connection fails
NSLog(#"Connection failed with error: %#",error.localizedDescription);
}
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{
/*This message is sent when there is an authentication challenge ,our server does not have this requirement so we do not need to handle that here*/
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Request Complete,recieved %d bytes of data",receivedData.length);
//[self.delegate requestReturnedData:receivedData];//send the data to the delegate
NSData *data = receivedData;
NSDictionary *dictionary = [NSDictionary dictionaryWithJSONData:data];
NSLog(#"%#",dictionary.JSONString ); ; // set the textview to the raw string value of the data recieved
NSString *value1 = [dictionary objectForKey:#"barcode"];
NSLog(#"%#", value1);
NSString *value2 = [dictionary objectForKey:#"product"];
NSLog(#"%#",dictionary);
NSLog(#"%#", value2);
}
Here's the log:
2013-01-10 16:31:46.550 Scanner[14875:907] http://server.nl/scan.php?data={"barcode":"123456"}
2013-01-10 16:31:46.551 Scanner[14875:907] url: <NSMutableURLRequest (null)>
2013-01-10 16:31:46.553 Scanner[14875:907] met value: <NSMutableURLRequest (null)>
**2013-01-10 16:31:46.556 Scanner[14875:907] Connection failed with error: bad URL**
When i delete the complete json from the string i get no bad url. So there might be the problem. Anyone know what i am doing wrong?
You need to encode it, before perfoming an URL request.
Best and most elegant solution would be adding a category over NSString for example, something like this:
- (NSString*)URLEncode {
// Should not be encoded:-_.
return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR(";/?:#&=+$,!*'()<>#%\"{}|\\^[]`~"), kCFStringEncodingUTF8) autorelease];
//
}
And when you make the request:
NSString *str = [NSString stringWithFormat: #"http://server.nl/scan.php?data=%#",jsonString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[str URLEncode]];
If you don't want to use additional files (even thought that would be recommended), add this method to your class:
- (NSString*)URLEncode:(NSString )yourURL {
// Should not be encoded:-_.
return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, NULL, CFSTR(";/?:#&=+$,!'()<>#%\"{}|\\^[]`~"), kCFStringEncodingUTF8) autorelease];
}
and use
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[self URLEncode:str]];
I don't have much information right now, I apologize, I'm in a bit of a hurry and just saw your question. But I saw your question and I remember working on a project which was essentially an HTML-based remote control for the iphone, and when the user clicked on some of the buttons for the remote, it followed the urls that opened up identical pages but had server-side code to instruct the server to pause, play, stop, etc... I DO remember that the iPhone had a bug that caused it to not be able to parse all of my URLs, even though they were correctly formatted and worked on a desktop client. That is why I switched over to POST requests (where user clicks instead activated javascript functions that set hidden form variables and then submitted forms rather than directly navigating to long URLS). Anyways, I know this may not directly apply to you, but the point is that I did find a bug in the iPhone's URL parsing, so it might not be your fault. I'll look up any new information I can find a little later. Good luck.

consuming restful web service in iOS 5

In my first ViewController (MonitorViewController) this is in the interface file MonitorViewController.h:
#import <RestKit/RestKit.h>
#interface MonitorViewController : UIViewController <RKRequestDelegate>
In MonitorViewController.m ViewDidLoad method, I have this at the end:
RKClient* client = [RKClient clientWithBaseURL:#"http://192.168.2.3:8000/DataRecorder/ExternalControl"];
NSLog(#"I am your RKClient singleton : %#", [RKClient sharedClient]);
[client get:#"/json/get_Signals" delegate:self];
The implementation of delegate methods in MonitorViewController.m:
- (void) request: (RKRequest *) request didLoadResponse: (RKResponse *) response {
if ([request isGET]) {
NSLog (#"Retrieved : %#", [response bodyAsString]);
}
}
- (void) request:(RKRequest *)request didFailLoadWithError:(NSError *)error
{
NSLog (#"Retrieved an error");
}
- (void) requestDidTimeout:(RKRequest *)request
{
NSLog(#"Did receive timeout");
}
- (void) request:(RKRequest *)request didReceivedData:(NSInteger)bytesReceived totalBytesReceived:(NSInteger)totalBytesReceived totalBytesExectedToReceive:(NSInteger)totalBytesExpectedToReceive
{
NSLog(#"Did receive data");
}
My AppDelegate method DidFinishLaunchingWithOptions method only returns YES and nothing else.
I recommend using RestKit framework. With restkit, you simply do:
// create the parameters dictionary for the params that you want to send with the request
NSDictionary* paramsDictionary = [NSDictionary dictionaryWithObjectsAndKeys: #"00003",#"SignalId", nil];
// send your request
RKRequest* req = [client post:#"your/resource/path" params:paramsDictionary delegate:self];
// set the userData property, it can be any object
[req setUserData:#"SignalId = 00003"];
And then, in the delegate method:
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response {
// check which request is responsible for the response
// to achieve this, you can do two things
// check the parameters of the request like this
NSLog(#"%#", [request URL]); // this will print your request url with the parameters
// something like http://myamazingrestservice.org/resource/path?SignalId=00003
// the second option will work if your request is not a GET request
NSLog(#"%#", request.params); // this will print paramsDictionary
// or you can get it from userData if you decide to go this way
NSString* myData = [request userData];
NSLog(#"%#", myData); // this will log "SignalId = 00003" in the debugger console
}
So you will never need to send the parameters that are not used on the server side, just to distinguish your requests. Additionally, the RKRequest class has lots of other properties that you can use to check which request corresponds to the given response. But if you send a bunch of identical requests, I think the userData is the best solution.
RestKit will also help you with other common rest interface tasks.

Resources