Discussion Forums  >  Plugins, Customizing, Source Code

Replies: 19    Views: 52

PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
05/13/14 10:57 PM (10 years ago)

My variables aren't 'sticking'...

Hi everyone, I have used a UITextField to capture a text string (NSString) and made it a declared variable. But because UITextField can only be created using a BOOL declaration, I think it's not allowing the value of the variable to be carried forward into other methods. How can I 'keep' the value of this variable for other methods to use it? Really stumped on this. eg this works fine: - (BOOL)textFieldShouldReturn:(UITextField *)textField { [self.tf resignFirstResponder]; NSString *userSearchQuery = (self.tf.text); NSLog(@"Our user search query is confirmed as %@", userSearchQuery); } //(in this case, userSearchQuery correctly shows up in the log to be whatever was entered into the text field.) but if I try to show the value of userSearchQuery again in another method's log, it tells me it has a null value: -(void)showMeThatThingAgain { NSLog(@"I wish I could but it's %@", userSearchQuery); } //(in this case, userSearchQuery is giving a null value). This is all within the same class file. Any ideas? Cheers Paddy
 
SmugWimp
Smugger than thou...
Profile
Posts: 6316
Reg: Nov 07, 2012
Tamuning, GU
81,410
like
05/14/14 12:40 AM (10 years ago)
At the risk of being drummed out of the forums… "If you think that is the only way to create a Text Field, you're full of Bool." ;) There. I said it. Actually, maybe that is the only way… but I would have used a UITextView right off the bat. With that, this should give you similar results, time after time… Let's say you've declared stuff in your header… ------ { UITextView *myTextView; } @property (nonatomic, retain) UITextView *myTextView; then, in your implementation file, in your favorite method, or however you desire, put some text in the text box... UITextView *myTextView = [[UITextView alloc] init]; [myTextView setText:@"bool-ony"]; implement a method to retrieve the text: -(NSString *)gimmeMyDarnTextYouVarmit:(UITextView *)theTextViewInMind { return theTextViewInMind.text; } and then, wherever you need to, you should be able to access it (within the same class) NSString *iGottaUseThisStringForSomething = [self gimmeMyDarnTextYouVarmit:myTextView]; [BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"This is the text from the Field: %@", iGottaUseThisStringForSomething]]; Or, I could completely be misunderstanding your question. Caveat Emptor. Cheers! -- Smug
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/14/14 01:09 AM (10 years ago)
haha, full of bool... (is that cheese I can smell?) Everything I've seen including the apple docs stick BOOL and UITextField together like you-know-what to a blanket. I thought that UITextView will only SET text as you've done there from within the code Smug, but I want to accept text as user input, which is why I'm using UITextField - as a search-bar-ish entry point that my app users can enter ANYTHING into. (There's a bit more code setting up the UITextField and its response to user input that I haven't shown; I've just posted the bit where the variable is assigned a value.) What I'm trying to do is -(BOOL) {show an empty UITextField and allow it to be populated with text that a user types in, then set that instance of their text as my NSString variable}, then -(void) {somehow grab that darned variable's value, and do something else with it} I hope that explains it better? I'm not sure you can have users enter data in a UITextView and then do anything with it apart from match a pre-set condition, can you? Cheers Paddy
 
Kittsy
buzztouch Evangelist
Profile
Posts: 2251
Reg: Feb 22, 2012
Liverpool
31,360
like
05/14/14 02:07 AM (10 years ago)
Paddy what you have done is correct in regards to settin up the textfield. Smug that method is a delegate method not teh setup and his textfield is called tf The reason you cannot access userSearchQuery is because it is only used in the method it was created it is not in scope. But you do not need to setup another variable as it will be stored in teh text property so you query method would be -(void)showMeThatThingAgain { NSLog(@"I wish I could but it's %@", self.tf.text); }
 
SmugWimp
Smugger than thou...
Profile
Posts: 6316
Reg: Nov 07, 2012
Tamuning, GU
81,410
like
05/14/14 03:08 AM (10 years ago)
I'm not aware if I've used a text Field before… UITextView more than once… But Kittsy's got a bit more going on with iOS than I do, so his example is probably the easiest way for you to go… Cheers! -- Smug
 
allandriggers
Apple Fan
Profile
Posts: 188
Reg: Dec 13, 2012
Knoxville, TN
11,680
like
05/14/14 10:42 AM (10 years ago)
Variable type of Bool isn't required for a UITextField but it is for a TextView unless it's an instance variable. But it looks like your are trying to dismiss the keyboard (ie....resignfirstresponder) in which the method would need to be a Bool.
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/14/14 04:33 PM (10 years ago)
Thanks everyone, that's great. Kittsy's suggestion is spot on and works nicely. My log now shows the value of userSearchQuery in flashing lights!! Allandriggers, yes, I'm hiding the keyboard once the user has entered their search term and hit return (or tapped the screen elsewhere) and then I'm using that search term to do other stuff (below). Can I ask someone to clarify something for me please: is it because of the BOOL requirement that this variable doesn't stay 'in scope', as you say Kittsy? Is there a way to keep a non-BOOL-created variable in scope throughout the entire class? I ask because I have other variables created on the fly and I definitely want to keep those passing through to another methods, and eventually use them in a php call - so they'll need to be sent with their variable name in the http request, not as self.something.value. Currently the routine that creates these variables sits as a snippet within this BOOL method, but I imagine I could set it as a new method, and call it with a @selector within this BOOL method if that approach will allow those variable values to persist. Kind of like this: -(BOOL)theKeyboardMethod {accept text input - the name of a city - and then dismiss the keyboard; store the city name text as NSString *userSearchQuery and show it on our log just to prove that we've captured it; call geoCodingMethod} -(int)geoCodingMethod {use Kittsy's self.tf.text suggestion to again define userSearchQuery, send it off to a geocoder; get the results of the geocoder query and set those as the values of two new lat/long NSString variables *myLat and *myLong; call theNextMethod} -(void)theNextMethod {do stuff using the two variables created in geoCodingMethod} Question is, (a) will that allow the values of *myLat and *myLong to persist throughout the class because they were created using a non-BOOL method, or (b) are variable values always only available within the method in which they were created no matter what type of method it is? If it's (b), how do I make them available throughout the class without re-defining them? Or is that what I need to do - re-define them every time I want to use them? (I hope not!!) Cheers Paddy
 
SmugWimp
Smugger than thou...
Profile
Posts: 6316
Reg: Nov 07, 2012
Tamuning, GU
81,410
like
05/14/14 04:39 PM (10 years ago)
A 'local' variable is only available within the method it was created… NSString *tmpString = @"As soon as the method is finished, this value goes bye-bye"; A 'class' variable is declared in the (.h) file, and synthesized in the (.m) file. It is available anywhere in the class. (.h) @property (nonatomic, assign) NSString *tmpString; (.m) @synthesize tmpString; (elsewhere in .m) -(void)showMeThatThingAgain { NSLog(@"I wish I could but it's %@", self.tf.text); tmpString = self.tf.text; } then elsewhere, you can call for the value of tmpString, and until you over write it (or quit the app) the value will remain in tmpString. In this instance, a class variable seems to be the easiest/quickest way... Cheers! -- Smug
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/14/14 04:44 PM (10 years ago)
Googling 'class variable' now... :) Cheers Paddy
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/14/14 05:00 PM (10 years ago)
Thanks Smug, that was exactly what I needed! (edit: ... works *sometimes*.... doesn't seem to want to pass the variable to all methods in the class - not sure why. Hmm.) One small step for most people, one giant step for me. ;) You guys are all awesome, I can't thank this community enough. Cheers Paddy.
 
Kittsy
buzztouch Evangelist
Profile
Posts: 2251
Reg: Feb 22, 2012
Liverpool
31,360
like
05/14/14 05:39 PM (10 years ago)
That's not a class variable it is a property. Also ovoid using tmp to prefix a property name as it's not really temporary. Keep properties and instance variables to a minimum most of the objects you are using have there own properties ie self.tf.text. References the text property of the UITextfield The cllocation you will create also has properties like longitude and latitude. Don't create what is already there. 1st method to launch when typing finished. Use self.tf.text with your get request to get co ordinates from your data base Parse the long and lat into a cllocation manager and go to on map. It's 2 or 3 methods tops and no added properties or instance variables
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/14/14 05:59 PM (10 years ago)
Hi Kittsy, I get what you're saying about being efficient and not re-defining stuff, it's 'parse the long and lat' etc that still has me scratching my head if I don't use Smug's suggestion. If the lat and long are returned in one method, and those values only 'exist' in that method, I'm not clear on how to pass them through to the final method that does something with them, because that final method hasn't been told what those values are. But setting them as properties would let all methods 'know' what they are, right? Cheers Paddy
 
Kittsy
buzztouch Evangelist
Profile
Posts: 2251
Reg: Feb 22, 2012
Liverpool
31,360
like
05/14/14 06:05 PM (10 years ago)
By the sounds if it you want to 1 user types a city name clicks return or dismisses keyboard 2 map then zooms to that location and shows nearby location pins Is that what you want
 
SmugWimp
Smugger than thou...
Profile
Posts: 6316
Reg: Nov 07, 2012
Tamuning, GU
81,410
like
05/14/14 06:36 PM (10 years ago)
You can pass both lat and lng if you create a CLLocationCoordinate2D and assign the values there… CLLocationCoordinate2D tmpCoordinates; tmpCoordinates.latitude = xx.xxxxxx; tmpCoordinates.longitude = xx.xxxxx; and you'll get them back similarly… tmpLat = tmpCoordinates.latitude; tmpLng = tmpCoordinates.longitude; Cheers! -- Smug
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/14/14 07:31 PM (10 years ago)
Kittsy yes that's exactly it. There are a few bits in between: 1. The default map is already showing what's around your current location [this works because there's an external dataURL specified in the BTconfig that's supplying those pins]. 2. You type in the name of another place because you want to look there instead. [this works too] 3. That new place name gets sent to Google's geocoding service which tells the app the lat and long of the new place [yep, working well]. 4. The new lat and long are passed into an NSURLRequest [current challenge] which runs a php script that queries a mySQL dbase [no problems]. It grabs all data entries within a set radius of the new lat and long and returns those [all good]. 5. The current map pins are removed [easy, done]. 6. The new pins get mapped in the new location [will work when current challenge is overcome!]. Smug I'd still need to have xx.xxxx sent in as an on the fly value, right? eg if I get my new lat and long like so (this works, no problems): -(void)geoCoder { NSString *cityRequest = [NSString stringWithFormat:@"http://maps.googleapis.com/maps/api/geocode/json?address=%@&sensor=true", userSearchQuery]; cityRequest = [cityRequest stringByReplacingOccurrencesOfString:@" " withString:@"%20"]; NSURL *cityURL = [NSURL URLWithString:cityRequest]; NSData *data = [NSData dataWithContentsOfURL: cityURL]; NSURLRequest *dataRequest = [NSURLRequest requestWithURL:cityURL]; // If we fail to get data from server if (nil == data) { NSLog(@"Error: the dumb server has not provided any data"); } else{ // Parse the json data NSError *error; NSURLResponse *response; NSData *responseData = [NSURLConnection sendSynchronousRequest: dataRequest returningResponse:&response error:&error]; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:nil]; NSString *cityLatResult=[[[[[dict objectForKey:@"results"] objectAtIndex:0]objectForKey:@"geometry"]objectForKey:@"location"]objectForKey:@"lat"]; NSString *cityLongResult=[[[[[dict objectForKey:@"results"] objectAtIndex:0]objectForKey:@"geometry"]objectForKey:@"location"]objectForKey:@"lng"]; // Now we have our city's lat and long geocoded. Spit them out in the log just to check: NSLog(@"Woohoo! The latitude=%@", cityLatResult); // it works!! NSLog(@"and OMFG, the longitude=%@", cityLongResult); // it works!! [self performSelector:(@selector(reloadData)) withObject:nil afterDelay:0.1]; } -(void) reloadData { // is going to include something like this NSString *newPoints = [NSString stringWithFormat:@"http://www.noshplanet.com/newpins.php?userlat=[cityLatResult]&userlong=[cityLongResult]]; newPoints = [newPoints stringByReplacingOccurrencesOfString:@" " withString:@"%20"]; NSURL *cityURL = [NSURL URLWithString:newPoints]; // and some more stuff happens } userlat and userlong are recognised in the php script so I want the values of cityLatResult and cityLongResult to be sent to the script. I just want reloadData to know what the values of cityLatResult and cityLongResult are, because its the method that's going to run the php for me - and you can see from my sequence above that it's the sticking point. Are you saying that I'd then set tmpCoordinates.latitude = cityLatResult? If I add that extra step in - will that make these lat/long values available to all? I'm a bit foggy on that. But I'll keep playing! Sorry if I'm not explaining this well. :( Cheers Paddy
 
Kittsy
buzztouch Evangelist
Profile
Posts: 2251
Reg: Feb 22, 2012
Liverpool
31,360
like
05/15/14 03:24 AM (10 years ago)
Rewrite the reloadData method like this or create a different one. I'm going off memory so code may not be syntax correctly -(void)reloadDataWithLatitude:(NSString *)latitude andLongitude:(NSString *)longitude{ NSString *newPoints = [NSString stringWithFormat:@"http://www.noshplanet.com/newpins.php?userlat=%@&userlong=%@",latitude,longitude]; newPoints = [newPoints stringByReplacingOccurrencesOfString:@" " withString:@"%20"]; NSURL *cityURL = [NSURL URLWithString:newPoints]; // and some more stuff happens } Then change method call from. This will pass the parameters [self performSelector:(@selector(reloadData)) withObject:nil afterDelay:0.1]; to [self reloadDataWithLatitude:cityLatResult andLongitude:cityLongResult];
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/15/14 05:07 PM (10 years ago)
Kittsy, you're a wizard - even the syntax was spot on. Thank you so much, that's opened up a whole new bunch of possibilities. Can I ask, in general, what the difference is between calling a method using < self performSelector:(@selector(method)) > vs < self method > - apart from the fact that it works in this case? Is there any reason why you would or wouldn't choose one over the other in a given situation? Thanks again! Cheers Paddy.
 
Kittsy
buzztouch Evangelist
Profile
Posts: 2251
Reg: Feb 22, 2012
Liverpool
31,360
like
05/15/14 11:42 PM (10 years ago)
You can't pass arguements with perform selector. There are a few other reasons . Perform selector can be risky and not thread safe. Note if you write a perform selector with a wrong method name it will give you only a yellow warning. If it's fired it will crash. It has it's used for delays and various beer tricks And all without making any variables or properties
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
05/16/14 12:32 AM (10 years ago)
Thanks mate, helpful AND educational all in one! Cheers Paddy
 
PaddyO
Lost but trying
Profile
Posts: 189
Reg: Sep 11, 2013
Geelong
5,190
like
08/20/14 04:21 PM (10 years ago)
Sorry, made a new post out of this, I think it was a separate question.
 

Login + Screen Name Required to Post

pointerLogin to participate so you can start earning points. Once you're logged in (and have a screen name entered in your profile), you can subscribe to topics, follow users, and start learning how to make apps like the pros.