I am using AFNetworking and creating a post request for which I require json feedback. The code below works however I have two main questions; where do I release the ActivityIndicator Manager? The second question is this code correct, being new I get confused with blocks so I really want to know if I am doing it right thing for optimum performance, even though it works.
NSURL *url = [NSURL URLWithString:#"mysite/user/signup"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
AFNetworkActivityIndicatorManager * newactivity = [[AFNetworkActivityIndicatorManager alloc] init];
newactivity.enabled = YES;
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
usernamestring, #"login[username]",
emailstring, #"login[email]",
nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"mysite/user/signup"parameters:params];
[httpClient release];
AFJSONRequestOperation *operation = [AFJSONRequestOperation operationWithRequest:request success:^(id json) {
NSString *status = [json valueForKey:#"status"];
if ([status isEqualToString:#"success"]) {
[username resignFirstResponder];
[email resignFirstResponder];
[self.navigationController dismissModalViewControllerAnimated:NO];
}
else {
UIAlertView *alert =[[UIAlertView alloc] initWithTitle:#"Login Unsuccessful"
message:#"Please try again"
delegate:NULL
cancelButtonTitle:#"OK"
otherButtonTitles:NULL];
[alert show];
[alert release];
}
}
failure:^(NSHTTPURLResponse *response, NSError *error) {
NSLog(#"%#", error);
UIAlertView *alert =[[UIAlertView alloc] initWithTitle:#"Login Unsuccessful"
message:#"There was a problem connecting to the network!"
delegate:NULL
cancelButtonTitle:#"OK"
otherButtonTitles:NULL];
[alert show];
[alert release];
}];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:operation];
NSLog(#"check");
}
Thank you very much for your help in advance :)
I know this question is a bit old, but I still wanted to contribute.
As steveOhh said, you should use [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES] to turn on the activity network indicator. It is a singleton, and hence it doesn't require you to manually alloc-init and release. As to the other question, I noticed you are missing some parameters in your block calls, also, you can do this, which is much cleaner code:
NSURL *url = [NSURL URLWithString:#"mysite/user/signup"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:url] success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
// your success code here
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
// your failure code here
}];
[operation start]; // start your operation directly, unless you really need to use a queue
Why not use this instead?
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
Hence there's no need to alloc and init
Can't say much on the other codes, just started out learning objective-C and AFNetworking.. :)
Regards,
Steve0hh
Related
I have parsed json. The result of json stored in array which contain list of video ID.
Now I want to parse another json which retrieve detail of video and this json will be parsed in loop videoIDArray.count times
Here is code:
- (void)viewDidLoad
{
[super viewDidLoad];
videoIDArray = [[NSMutableArray alloc] init];
viewArray = [[NSMutableArray alloc] init];
//======Json Parsing
NSString *urlstring = [NSString stringWithFormat:#"https://myURL/youtubeList"];
NSURL *url = [NSURL URLWithString:urlstring];
NSURLRequest *Request = [NSURLRequest requestWithURL:url];
conn = [[NSURLConnection alloc] initWithRequest:Request delegate:self];
if (conn) {
webdata = [[NSMutableData alloc] init];
}
//==========
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (connection==conn) {
[webdata setLength:0];
}
if (connection==conn2) {
[webdata2 setLength:0];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (connection==conn) {
[webdata appendData:data];
}
if (connection==conn2) {
[webdata2 appendData:data];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//-------conn getting list of videoID
if (connection == conn) {
NSString *str = [[NSString alloc] initWithBytes:[webdata bytes] length:[webdata length] encoding:NSUTF8StringEncoding];
NSDictionary *Result = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
[videoIDArray addObjectsFromArray:[[[Result valueForKey:#"items"] valueForKey:#"id"] valueForKey:#"videoId"]];
NSLog(#"Video ID %#",videoIDArray);
//======conn2 is for getting detail of video base on videoID object
for (int i=0; i<videoIDArray.count; i++) {
NSString *urlstring = [NSString stringWithFormat:#"https://mydetailURL/videos/%#?v=2&alt=json",[videoIDArray objectAtIndex:i]];
NSURL *url = [NSURL URLWithString:urlstring];
NSURLRequest *Request = [NSURLRequest requestWithURL:url];
conn2 = [[NSURLConnection alloc] initWithRequest:Request delegate:self];
if (conn2) {
webdata2 = [[NSMutableData alloc] init];
}
}
//==========
}
if (connection==conn2) {
[MBProgressHUD hideHUDForView:self.view animated:YES];
[youtubeTableView reloadData];
NSString *str = [[NSString alloc] initWithBytes:[webdata bytes] length:[webdata length] encoding:NSUTF8StringEncoding];
NSDictionary *Result = [NSJSONSerialization JSONObjectWithData:[str dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
NSLog(#"ResultConn2 %#",Result);
[viewArray addObject:[[[Result valueForKey:#"entry"] valueForKey:#"yt$statistics"] valueForKey:#"viewCount"]];
NSLog(#"View Array %#",viewArray);
}
}
Problem is: it is not parsing as many times as in loop, only for last one connectionDidFinishLoading method called and crashed..
Can somebody tell me how to do this?
Is there any other way to do this?
EDIT
With AFNetworking
i changed my code like:
for (int i=0; i<videoArray.count; i++) {
[self parseWithUrl:[videoArray objectAtIndex:i]];
}
-(void)parseWithUrl: (NSString *)urlstr
{
NSString *tstr=[urlstr stringByReplacingOccurrencesOfString:#"\"" withString:#""];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://myURL/feeds/api/videos/%#?v=2&alt=json",tstr]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
//instead of NSLog i want to return result
NSDictionary *result = (NSDictionary *)JSON;
NSLog(#"VideoResult %#",result);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}];
[operation start];
}
I want to write:
-(NSDictionary *)parseWithUrl: (NSString *)urlstr
Is it possible?
if Yes then suggest me where i should return result?
if i want to call another method after completing json then where to write call code
here is my code:
[self getData:self.weather];
my method called number of times which i don't want.
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.weather = (NSDictionary *)JSON;
[self getData:self.weather];
.....
.....
}
Your issue stems from the fact that each of these NSURLConnection connections run asynchronously and therefore you're running many requests concurrently, but your routine is using a single webData2, so your requests are tripping over each other.
If you want to stay with your current design, rather than having a for loop where you initiate all of the second set of requests, you should only request the first one. And then have the connectionDidFinishLoading for the second type of request initiate the next one. (You could manage this "next" process by keeping track of some numeric index indicating which request you're processing, incrementing it each time.)
But you ask how to do these requests sequentially, one after another. Is there any reason why you cannot do them concurrently (more accurately, when first request is done, then issue the detail requests for the individual videos concurrently). In that scenario, even better than the clumsy fix I outlined in the prior paragraph, a more logical solution is an NSOperation-based implementation that:
Uses a separate object for each connection so the individual requests don't interfere with each other;
Enjoys the concurrency of NSURLConnection, but constrains the number of concurrent requests to some reasonable number ... you will yield significant performance benefits by using concurrent requests; and
Is cancelable in case the user dismisses the view controller while all of these requests are in progress and you want to cancel the network requests.
If you're already familiar writing NSURLConnectionDataDelegate based code, wrapping that in an NSOperation is not much worse. (See Defining a Custom Operation Object in the Concurrency Programming Guide.) We can walk you through the steps to do that, but frankly much easier is to use AFNetworking. They've done the complicated stuff for you.
In your edit to your question, you ask whether it is possible to write:
- (NSDictionary *)parseWithUrl: (NSString *)urlstr
While it's technically possible to, you never want a method on the main queue waiting synchronously for a network request. If parseWithURL cannot do what it needs to do inside the success block of the AFNetworking call (e.g. you might initiate a [self.tableView reloadData] or whatever is needed for your UI), then have parseWithURL return the dictionary in a completion handler of its own, e.g.:
- (void)parseWithURL: (NSString *)urlstr completion:(void (^)(NSDictionary *))completion
{
...
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
completion(JSON); // call the completion block here
} failure:...];
}
Finally I am done parsing synchronous multiple json parsing with help of AFNetworking
Success of json parsing call another method in AFNetworking done by: link
Here is Code:
- (void)getResponse:(void (^)(id result, NSError *error))block {
NSString *weatherUrl = [NSString stringWithFormat:#"%#weather.php?format=json", BaseURLString];
NSURL *url = [NSURL URLWithString:weatherUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 2
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
// 3
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
//Success
block(JSON,nil); //call block here
}
// 4
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}];
// 5
[operation start];
}
calling will be:
[self getResponse:^(id result, NSError *error) {
//use result here
}];
I am communicating with server in my ios app. I have following method in which I'm opening an alertview. I want to show a loading view while app is getting response from the server.
- (void) showDetailedQuestion:(id)sender
{
//loading view
self.loading_alert = [[UIAlertView alloc] initWithTitle:#"Loading\nPlease Wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles: nil];
[self.loading_alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Adjust the indicator so it is up a few pixels from the bottom of the alert
indicator.center = CGPointMake(loading_alert.bounds.size.width / 2, loading_alert.bounds.size.height - 50);
[indicator startAnimating];
[self.loading_alert addSubview:indicator];
UIButton *btn = (UIButton*)sender;
int indx = btn.tag;
NSLog(#"tag:%d",indx);
answerAnQuestion *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"Answer"];
vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal ;
vc.que_id = [self.que_id valueForKey:[NSString stringWithFormat:#"%d",indx]];
vc.qid_list = self.que_id;
vc.crnt = indx;
[self presentViewController:vc animated:YES completion:nil];
[self.loading_alert dismissWithClickedButtonIndex:0 animated:YES];
}
and in another answerAnQuestion.m
- (void)viewDidLoad
{
NSString *address = [NSString stringWithFormat:#"%#%#%#%#%#%#%#", path,#"questions/",que_id,#"?token=",token,#"&user_id=",usrId];
NSURL *URL = [NSURL URLWithString:address];
NSLog(#"%#",address);
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[URL host]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLCacheStorageAllowedInMemoryOnly
timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
responseData = [[NSMutableData alloc] init];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (data)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*) response;
//If you need the response, you can use it here
int statuscode = [httpResponse statusCode];
NSString *responseMsg = [NSHTTPURLResponse localizedStringForStatusCode:statuscode];
NSLog(#" Status code: %d",statuscode );
NSLog(#" Status msg: %#",responseMsg );
}
else
{
// Handle error by looking at response and/or error values
NSLog(#"%#",error);
}
}
My problem is alertview is only shown up for a moment when view is changing. It suppose to open when I click the button. What could be the reason? how to solve this?
EDIT 1:
If i make asynchronous request to server then i'm not able to set those data in my tableview. I can set those data in my tableview Only if send synchronous request,but it blocks the app. Why this is happening ?
Any help will be appreciated.
Thank you.
You are sending SynchronousRequest on main thread, so it is blocking your UI thread. Read multithreading you will get various tutorial on this. I can suggest you to go for GCD or NSOperation and NSOperationQueue. Google for any of the above and you will get various sample for the same.
Or you can send asynchronous request as follows...
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//Like dismissing loading view and populating UI.
}];
Updated:
//Display alert view, before sending your request..
[alertview show];
//send first request
[NSURLConnection sendAsynchronousRequest:request1 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send second request
[NSURLConnection sendAsynchronousRequest:request2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//send third request
[NSURLConnection sendAsynchronousRequest:request3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//Write code you want to call when data is received,
//dismiss alert view on main thread
dispatch_async(getmainqueue, ^(void) {
// dismiss alert view...
});
}];
}];
}];
I have worked with Nuzhat Zari code, and I thank him for it, but also have experienced some issues with some core data operations between nested "sendAsynchronousRequest" (getting some weird thread and memory errors) so, my solution was unnest the calls to "sendAsynchronousRequest" and use some main thread variable validation.
#interface myMainThreadClass
#property (nonatomic,assign) NSInteger *currentAsyncTasks;
#end
#implementation
// Use init or viewDidLoad to make "currentAsyncTasks=0"!!
-(void)method
{
[self showLoadingAlert]; //or some ui update function
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest2 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
currentAsyncTasks++;
[NSURLConnection sendAsynchronousRequest:urlRequest3 queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
//do something with data
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self dismissAlertInFinalTask]
});
}];
}
-(void)dismissAlertInFinalTask
{
currentNetworkTasks--;
if (currentNetworkTasks == 0)
{
[self dismissLoadingAlert];//or some ui update function;
}
}
#end
I also want to know if someone has managed to do multiple request using NSURLConnection delegate NSURLConnectionDataDelegate and ui calls.
I am building a chat application which repeatedly calls a web service using AFNetworking. The chat screen constantly polls this service for new chat messages. Everything related to the service works fine, but the UI keeps freezing and none of the buttons are working.
Here is the code:
- (void)GetAllIncomingMessages
{
NSURL *url = [NSURL URLWithString:weatherUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[self ParseJson:(NSDictionary *)JSON];
[self GetAllIncomingMessages];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
{
[self GetAllIncomingMessages];
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error "
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}];
[operation setAuthenticationChallengeBlock:
^( NSURLConnection* connection, NSURLAuthenticationChallenge* challenge )
{
if( [[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodHTTPBasic )
{
if( [challenge previousFailureCount] > 0 )
{
// Avoid too many failed authentication attempts which could lock out the user
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
else
{
[[challenge sender] useCredential:[NSURLCredential credentialWithUser:#"username" password:#"password" persistence:NSURLCredentialPersistenceForSession] forAuthenticationChallenge:challenge];
}
}
else
{
// Authenticate in other ways than NTLM if desired or cancel the auth like this:
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
}];
[operation start];
}
I reload the table view each time, but the UI still freezes. I tried using a background thread and that didn't work either.
I know this is an old question but I just bumped into it. Just FYI AFNetworking use a dispatched async queue to perform the connection operation and give back to you a JSON format of the NSData retrieved (as you probably already know) in the main queue. So AFNetworking is definitely not the problem.
My suggestion is try to perform ParseJson: and GetAllIncomingMessages: in a separated thread or dispatch an async queue yourself and you'll see your UI no longer freezing.
Something like:
static dispatch_queue_t your_app_queue() {
static dispatch_once_t onceToken;
static dispatch_queue_t _myQueue;
dispatch_once(&onceToken, ^{
_myQueue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_SERIAL);
});
return _myQueue;
}
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
__block myClass = self;
dispatch_async(your_app_queue(), ^{
[myClass ParseJson:(NSDictionary *)JSON];
[myClass GetAllIncomingMessages];
});
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
__block myClass = self;
dispatch_async(your_app_queue(), ^{
[myClass GetAllIncomingMessages];
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error "
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
});
});
}];
Or:
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest: nil
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
[self performSelectorInBackground:#selector(ParseJson:) withObject:JSON];
[self performSelectorInBackground:#selector(GetAllIncomingMessages) withObject:nil];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
[self performSelectorInBackground:#selector(GetAllIncomingMessages) withObject:nil];
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error "
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
}];
And should be fine. Hope this help!
I am developing a app which upload multiple files.
For uploading, I use AFHTTPRequestOperation. It successfully works, But If I lock and after it unlock the screen,then It stop uploading files.
My code for upload file is here
NSUserDefaults *defaultUser = [NSUserDefaults standardUserDefaults];
NSString *userId = [defaultUser stringForKey:#"UserId"];
AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",UploadURL,userId]]];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:nil];
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:#"POST" path:nil parameters:params constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
[formData appendPartWithFileData: data name:#"f" fileName:[NSString stringWithFormat:#"%d_image.jpeg",rand()] mimeType:#"image/jpeg"];
}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", [operation error]);
if(error.code == -1001){
UIAlertView *myAlert = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"The request timed out." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[myAlert show];
}
}];
[operation start];
Can anyone give me suggestion for handle this situation.
Thanks.
(1) Add this code:
[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^{
// Handle iOS shutting you down (possibly make a note of where you
// stopped so you can resume later)
}];
(2) Change this line:
[operation start];
to
[client enqueueHTTPRequestOperation:operation];
(3) Keep a strong reference to your AFHTTPClient (this is typically done for AFHTTPClient with the singleton pattern) so that your operations don't get deallocated
What could this error mean?
[__NSCFNumber length]: unrecognized selector sent to instance 0x6d21350
Here is my code:
NSString *urlString = #"http://api.twitter.com/1/statuses/update.json";
NSURL *url = [NSURL URLWithString:urlString];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
[params setObject:status forKey:#"status"];
[params setObject:replyToID forKey:#"in_reply_to_status_id"];
[params setObject:#"1" forKey:#"include_entities"];
// Build the request with our parameter
TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:params requestMethod:TWRequestMethodPOST];
// Attach the account object to this request
[request setAccount:twitterAccount];
[request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (!responseData) {
// inspect the contents of error
NSLog(#"%#", [error localizedDescription]);
self.alert = [[UIAlertView alloc] initWithTitle:#"HTTP error" message:#"I could not connect to the Twitter API." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[self.alert show];
[self.replyDelegate replyRequestSuccessful:NO];
}
else {
/*NSString *responseDataAsString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(responseDataAsString);*/
NSError *error;
NSArray *replyResponse = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableLeaves error:&error];
if (!replyResponse) {
NSLog(#"%#", [error localizedDescription]);
self.alert = [[UIAlertView alloc] initWithTitle:#"JSON error" message:#"I could not parse the JSON response from the Twitter API." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[self.alert show];
[self.replyDelegate replyRequestSuccessful:NO];
}
else {
[self.replyDelegate replyRequestSuccessful:YES];
}
}
}];
I tried debuggin, and it dies once it enters the performRequestWithHandler. It goes the else block and dies with the error above.
It means that you are passing an NSNumber where the called code expects an NSString or some other object that has a length method. You can tell Xcode to break on exceptions so that you see where exactly the length method gets called.
Specifically this line of code:
[params setObject:replyToID forKey:#"in_reply_to_status_id"];
the replyToID is not a String or has a method length. If you don't have this, or if you convert the replyToID to a String before setting it in params it should work.