NSMutableData - unrecognized selector sent to instance - ios

I am trying to get data from response.
I'm using NSURLConnectionDelegate, NSURLConnectionDataDelegate.
The project uses ARC.
#interface MainMenu()
#property (nonatomic, unsafe_unretained) NSMutableData* wpData;
#end
#implementation
-(void)sendRequest{
NSURL* url = [[NSURL alloc] initWithString:#"http://smthing"];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] init];
NSString* reqBody = #"Block";
NSData* reqData = [reqBody dataUsingEncoding:NSUTF8StringEncoding];
[request setURL:url];
[request setHTTPBody:reqData];
[request setHTTPMethod:#"POST"];
self.wpData = [NSMutableData data];
NSURLConnection* conection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conection start];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
//Here iI have [__NSMallocBlock__ appendData:]: unrecognized selector sent to instance 0x95f3fb0
[self.wpData setLength:0];
}
#end
Maybe you can found my mistake
Thanks :)

Your data pointer is an unsafe_unretained property,
#property (nonatomic, unsafe_unretained) NSMutableData* wpData;
and you are assigning it a autoreleased instance,
self.wpData = [NSMutableData data]; //Returns autoreleased object
Since you are making asynchronous download request you require to maintain the data object.
You never know when the autorelease pool will be flushed and the unretained object will go out of scope. In such situations you should retain the autoreleased object. Change the property to strong and allocate the data object,
#property (nonatomic, strong) NSMutableData* wpData;
//...
self.wpData = [[NSMutableData alloc] init]; //Better practice
Hope that helps!

Related

Objective C UITextField values blank

I am trying to get the values from a few UITextFields I have added to my storyboard and send them as a JSON string to an API. I can hard code the values for the JSON string and everything works fine. Now I want to retrieve the values from the text fields and insert them in place of the hard coded values. The problem is that when I log the values to the console they are showing up as blank. I am not sure that I have the code correct to get the values from the ViewController to the method that sends the data. I followed several tutorials on how to get the data from the ViewController UITextFields. I connected the text fields to the properties in the ViewController.h file. I am hoping someone can help me figure out what I did wrong, hopefully I provided enough information.
I think the problem may be how I am trying to get the values from these lines of code in the timeMethods.m file:
ViewController *controller = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
NSString *name = controller.name.text;
NSString *type = controller.type.text;
NSString *date = controller.date.text;
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (nonatomic, retain) IBOutlet UITextField *name;
#property (nonatomic, retain) IBOutlet UITextField *type;
#property (nonatomic, retain) IBOutlet UITextField *date;
#end
ViewController.m
#import "ViewController.h"
#import "timeMethods.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize name;
#synthesize type;
#synthesize date;
- (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.
}
- (IBAction)sendRequest:(id)sender {
[[timeMethods alloc] sendRequest];
}
- (IBAction)getRequest:(id)sender {
[[timeMethods alloc] getRequest];
}
#end
timeMethods.m
#import "timeMethods.h"
#implementation timeMethods
- (void)sendRequest {
ViewController *controller = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
NSString *name = controller.name.text;
NSString *type = controller.type.text;
NSString *date = controller.date.text;
NSURL *url = [NSURL URLWithString:#"http://throttle.com/my-rest-api/api/robots"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
name, #"name",
type, #"type",
date, #"year",
nil];
NSError *error;
NSData *postData = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
[request setHTTPBody:postData];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)[postData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: postData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
NSString *strData = [[NSString alloc]initWithData:postData encoding:NSUTF8StringEncoding];
NSLog(#"%#", strData);
}
- (void)getRequest {
NSString *serverAddress = #"http://throttle.com/my-rest-api/api/robots";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:serverAddress]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
[request setHTTPMethod:#"GET"];
NSError *requestError;
NSURLResponse *urlResponse = nil;
NSData *response1 = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
NSString *strData = [[NSString alloc]initWithData:response1 encoding:NSUTF8StringEncoding];
NSLog(#"%#",strData);
}
#end
timeMethods.h
#import <Foundation/Foundation.h>
#interface timeMethods : NSObject
- (void)sendRequest;
- (void)getRequest;
#end
The trouble is that we've just allocated a brand new VC and asked for its UITextField's values here:
ViewController *controller = [[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
// controller.name is a brand new text field, created in the previous line
NSString *name = controller.name.text; // guaranteed to be #""
Of course this will be an empty text field. It was created in the previous line. Instead, get those values as params to your request from the view controller the user is using...
- (IBAction)sendRequest:(id)sender {
NSString *name = self.name.text;
NSString *type = self.type.text;
NSString *date = self.date.text;
[[timeMethods alloc] sendRequestWithName:name type:type date:date];
}
Naturally, add those parameters to the sendRequest method and remove the local vars.

The correct way asynchronously call an object?

I have hobbled together one of my first objects. The goal of the object is to send a text message, which is does. However I'm calling it from the 2nd UIViewController within ViewDidLoad, and its still hanging within the Segue transition. So I know I need to get it asynchronously, but reading some other threads they implied that the proper way to go around it is to make it an "AppDelegate Object", so I would assume I would need to call the object from the AppDelegate, but I'm not really sure about how to go about that as I have not really worked with that in some tutorials I'm doing, and on top of that, is that the correct way to go about using my object?
initializing the object from my view controller
Twilio *twilio = [[Twilio alloc] init];
[twilio sendMessage: self.phoneNumber: [self getRandomNumberBetween:1000 to:9999]];
Header file
#import <Foundation/Foundation.h>
#interface Twilio : NSObject
#property (strong, nonatomic) NSString *TwilioSID;
#property (strong, nonatomic) NSString *TwilioSecret;
#property (strong, nonatomic) NSString *FromNumber;
#property (strong, nonatomic) NSString *ToNumber;
#property (strong, nonatomic) NSString *Message;
-(id)init;
-(id)sendMessage:(NSString *)phoneNumber :(NSString *)message;
#end
Implementation file
#import "Twilio.h"
#implementation Twilio
-(id)init {
self = [super init];
if(self) {
// Twilio Common constants
self.TwilioSID = #"A....3";
self.TwilioSecret = #"e...8";
self.FromNumber = #"5...2";
self.ToNumber = nil;
self.Message = nil;
}
return self;
}
-(id)sendMessage:(NSString *)phoneNumber :(NSString *)message
{
NSLog(#"Sending request.");
self.ToNumber = phoneNumber;
self.Message = message;
// Build request
NSString *urlString = [NSString stringWithFormat:#"https://%#:%##api.twilio.com/2010-04-01/Accounts/%#/SMS/Messages", self.TwilioSID, self.TwilioSecret, self.TwilioSID];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
// Set up the body
NSString *bodyString = [NSString stringWithFormat:#"From=%#&To=%#&Body=%#", self.FromNumber, self.ToNumber, self.Message];
NSData *data = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:data];
NSError *error;
NSURLResponse *response;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// Handle the received data
if (error) {
NSLog(#"Error: %#", error);
} else {
NSString *receivedString = [[NSString alloc]initWithData:receivedData encoding:NSUTF8StringEncoding];
NSLog(#"Request sent. %#", receivedString);
}
return self.Message;
}
#end
Updated
With recommendation below I changed my object implementation like so:
//NSError *error;
//NSURLResponse *response;
//NSData *receivedData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
[NSURLConnection sendAsynchronousRequest:request queue:self.queue completionHandler:^(NSURLResponse *response, NSData *data, NSError
*error) {
// Handle the received data
if (error) {
NSLog(#"Error: %#", error);
} else {
NSString *receivedString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Request sent. %#", receivedString);
}
NSLog(#"%#",response);
}];
Use method sendAsynchronousRequest:queue:completionHandler:
See it : https://stackoverflow.com/a/9270711/2828120

Setting Property Variables in Class Methods

Currently, I understand that I cannot set Property Variables within a class method.
For Example:
#ISUser.h
#interface ISUser : NSObject
#property (nonatomic, retain) NSString *username;
#property (nonatomic, retain) NSString *password;
#property (nonatomic, retain) NSString *email;
#property (nonatomic, retain) NSString *firstname;
#property (nonatomic, retain) NSString *lastname;
+ (void)logInWithUsernameInBackground:(NSString *)username
password:(NSString *)password
block:(ISUserResultBlock)block;
#end
I am looking through Parse's framework and am trying to get a better understanding of how to implement a login like they have done. The class method (void)logInWithUsernameInBackground:password:block is where I attempt to assign the property variables username and password but it's a no go.
Here is the implementation of the current method:
+ (void)logInWithUsernameInBackground:(NSString *)username password:(NSString *)password block:(ISUserResultBlock)block
{
//self.username = username // Of course, I cannot do this
NSString *preferredLanguageCodes = [[NSLocale preferredLanguages] componentsJoinedByString:#", "];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#%#", kAPIHost, kAPIPath]]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:[NSString stringWithFormat:#"%#, en-us;q=0.8", preferredLanguageCodes] forHTTPHeaderField:#"Accept-Language"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSData * data = [[NSString stringWithFormat: #"command=login&username=%#&password=%#", username, password] dataUsingEncoding: NSUTF8StringEncoding];
[request setHTTPBody:data];
ConnectionBlock *connection = [[ConnectionBlock alloc] initWithRequest:request];
[connection executeRequestOnSuccess: ^(NSHTTPURLResponse *response, NSString *bodyString, NSError *error) {
block([self user], error);
} failure:^(NSHTTPURLResponse *response, NSString *bodyString, NSError *error) {
block([self user], error);
}];
}
Within the parse PFUser.h file, this is a class method... But how do they assign the property variables?
I know that static variables can be assigned/set within a class method but I would like to access such variables from another class.
EDIT: After viewing the first comment, The ISUser class has a singleton already implemented.
+ (instancetype)currentUser
{
static ISUser *sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
But now what? I need to override the init method and set the variables? But how does the init method know what to set the variables to? Will I have to add parameters to the + (instancetype)currentUser like so + (instancetype)currentUser:username password:(NSString *)password then override the init method as well? + (instancetype)currentUser is another class method that I pulled from the PFUser framework.
You can not set properties in class method. You can do it on instance methods. Thats because properties are for instances of the class.
In the parse login method they use some properties as method parameters and use them for the login process, but not manipulate them.
Hope it helps

Thread still running of old view

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.
}

NSMutableData disappearing

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

Resources