Use an If statement with the button name in Objective-C (Cocoa/iPhone SDK) - objective-c

I have to implement a small feature in an iPhone app and was wondering if there was a way to do use an if statement where the condition is the string of a button.
Here’s a sample of the code in question:
- (IBAction)someMethod:(id)sender{
UIButton *button = (UIButton *)sender;
if ( button.titleLabel.text == “SomeText” )
{
//do something
}
else
{
// some other thing
}
Now I can’t make it work, because I think I’m using the wrong code in button.titleLabel.text. I’ve even tried #“SomeText”), but I always end up in //some other thing.
What am I doing wrong?
Thanks.

What you're currently doing is comparing two pointers to objects, the objects button.titleLabel.text and #"SomeText". As both point to different places in the memory, the comparison will return NO.
If you want to compare the values of both NSString objects, however, you can use [button.titleLabel.text isEqualToString:#"SomeText"].
Also note that "SomeText" is not the same as #"SomeText"! The first is a regular C string, where the last one is a Cocoa NSString object.

Related

Programmatically selecting a segment in UISegmentedControl based on title of that segment

I have a UISegmentedControl with several segments, each with a different "title". I want to be able to read in a NSString, and programmatically select the segment whose title matches that string. Say I start with something like:
NSString *stringToMatch = #"foo";
UISegmentedControl *seg = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"foo",#"bar",#"baz", nil]];
I want to do something like:
[seg selectSegmentWithTitle:stringToMatch];
But since there is no method called selectSegmentWithTitle, this doesn't work. Is anyone aware of a method that would be similar to this though?
I've also thought of looping over all the titles in seg, similar to this:
int i = 0;
for (UISegment *thisSeg in [seg allSegmentsInOrder])
{
if ([thisSeg.title isEqualToString:stringToMatch])
{
[seg setSelectedSegmentIndex:i];
break;
}
i++;
}
but to my knowledge there is no such thing as UISegment, nor is there a method allSegmentsInOrder. Again, does anyone know of any changes I could make to get this to work?
Thirdly, I could probably subclass UISegmentedControl to somehow add the methods I want it to have. I hate subclassing like that though, cause I'd have to go and re-declare all my segments and other inconvenient things like that. But it may be the only way to go...
Perhaps the way to do this is totally different from the three ideas I listed above. I'm open to whatever.
So while I was typing this question up, I kept searching and realized that my second method from OP is pretty close. I figured I should still post what I came up with, in case someone else is looks for something like this in the future.
for (int i = 0; i < [seg numberOfSegments]; i++)
{
if ([[seg titleForSegmentAtIndex:i] isEqualToString:stringToMatch])
{
[seg setSelectedSegmentIndex:i];
break;
}
//else {Do Nothing - these are not the droi, err, segment we are looking for}
}
if ([seg selectedSegmentIndex] == -1)
{
NSLog(#"Error - segment with title %# not found in seg",stringToMatch);
NSLog(#"Go back and fix your code, you forgot something");
// prob should do other stuff here to let the user know something went wrong
}
This still feels a little hacky, and is probably against some best practice guide somewhere, but if there's a finite list of titles and you can be certain stringToMatch will always be on that list, I'm thinking it should be fine.

Execute selector to find UIImageView using concatenated NSString

I'm new to Objective-C so sorry if this is a newbie question.
I've searched for a couple of hours and can't seem to find an answer to my question.
So I'm trying to access a UIImageView so I can hide/unhide it by concatenating strings together to get the name of the UIImageView which should hide/unhide.
I have it working by doing:
self.faceItemEyesFrightened.hidden = false;
However the Frightened part of the name could be different each time a button is clicked so, trying to refactor my code I run a function which returns the type of UIImageView should be affected.
So I have the following:
NSString *fullEmotionString = [#"faceItemEyes" stringByAppendingString:emotionIs];
where emotionIs would be Frightened, therefore forming
faceItemEyesFrightened
So my problem comes when I wish to do something like this:
self.fullEmotionString.hidden = false;
Obviously that's not the right way of doing it but I'm not sure how it should be done, any advice greatly appreciated.
Cheers!
You could use NSSelectorFromString like this:
SEL selector = NSSelectorFromString(fullEmotionString);
UIImageView *imageView = [self performSelector:selector];
imageView.hidden = NO;
Note, that this requires a getter called faceItemEyesFrightened to be defined, which is usually this case if you're using properties and didn't change the name of the accessors.
That being said, I think this is not an optimal solution to your problem.
You could for instance subclass UIImageView and add an enum MyImageViewEmotion that describes the emotion in the image. Then, instead of using lots of variables, like faceItemEyesFrightened or faceItemEyesHappy, you could put all of them in a simple array and then get one of them like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.emotion == %ld",
MyImageViewEmotionFrightened];
MyImageView *imageView = [eyeImageViews filteredArrayUsingPredicate:predicate][0]
Of use an NSDictionary, where you put the emotion string as the key and the image views as the value. Then you could access them very easily:
UIImageView *imageView = emotionViewDictionary[#"Frightened"];
By the way, boolean values in Objective-C are called YES and NO and not true and false.

How to display data in a nscombobox in cocoa?

I have an NSComboBox in my mainmenunib file.
I have created an outlet of combobox "cb" and made a connection of it with my delegate
I also connected delegate and datasource with my delegate.
-(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{ arr=[NSMutableArray arrayWithObjects:#"a",#"b",#"c",#"d",#"e",#"f", nil];
[cb reloadData];
}
-(NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox{
return arr.count;
}
-(id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)loc{
return [arr objectAtIndex:loc];
}
But when I run the application data is not coming in combobox.
Please help me out as i am new to cocoa programming.
Thanks in advance.
Your approach seems reasonable on the face of it, though using a mutable object as an instance variable is often ill-advised (for reasons wholly unrelated to your issue here, and which we needn't get into at this stage).
There are two things that jump out as possible issues:
1) Are you using ARC? If not, arr is going to disappear from under you because -arrayWithObjects returns an autoreleased object and you have nothing retaining it. If you are using ARC (the default for new project on Lion, I believe), this doesn't apply to you. Plus I would expect you would crash, not just get no data.
2) More likely, you forgot to -setUsesDataSource:YES, which is the flag that tells NSComboBox whether to look at its data source or to use the internal contents approach that #JustinBoo supplied. I believe this defaults to NO, which would cause your exact problem. I don't have Interface Builder in front of me at the moment, but IIRC there is a "uses data source" checkbox that you can check to enable this attribute.
You can add objects using -addItemWithObjectValue to Your NSComboBox like this:
arr = [NSMutableArray arrayWithObjects:#"a",#"b",#"c",#"d",#"e",#"f", nil];
for (int i = 0; i < [arr count]; ++i)
{
[cb addItemWithObjectValue:[arr objectAtIndex:i]];
}
You can see NSComboBox Reference for more information.

How to choose a method based on an element of an NSArray (Objective-C)

I'm writing a sort of calculator app. I have a UIPickerView (1 column) loading data from an NSArray of strings. The user will select one of these (it's selecting which type of calculator to use -- each uses a different method to calculate). The user inputs some things into some UITextFields and then presses a UIButton to do the calculations.
My NSArray is this:
calcNames = [NSArray alloc] initWithObjects:#"first", #"second", #"third", nil];
And my methods are called firstCalc(input1, input2, input3), secondCalc(input1, input2, input3), and so on. (The inputs are coming from the UITextFields.)
When I press the button, I would like to tell it to look at what the selection in the UIPickerView is and run the corresponding method without just typing an if-then statement for each one (it's very inconvenient to do this for reasons specific to my app, which are beyond the scope of this discussion).
So I have already defined a way to determine what the selected calc is:
selectedCalc = [[NSString alloc] initWithString:[calcNames objectAtIndex:row]]
where 'row' is the current selection in the UIPickerView.
Now I have a doCalculations method for when someone presses the UIButton:
-(IBAction)doCalculations:(id)sender {
// save the data input
double input1 = [input1Field.text doubleValue];
double input2 = [input2Field.text doubleValue];
double input3 = [input3Field.text doubleValue];
// do the calculations
int i;
for (i = 0; i < [calcNames count]; i++) {
if (selectedCalc == [calcNames objectAtIndex:i]) {
// do calculations here
double numResult = ??????
// if selectedCalc is "first", I want it to do firstCalc(input 1, input 2, input 3)
// if selectedCalc is "second", I want it to do secondCalc(input 1, input 2, input 3), and so on
// the rest is just for displaying the result
NSString* result = [NSString stringWithFormat:#"The answer is %f", numResult];
[resultLabel setText:result];
}
}
}
So basically, it runs a for loop until it finds which calculator is selected from the UIPickerView and when it finds it, runs the calculations and displays them.
I've been trying to understand if maybe function pointers or selectors (NSSelectorFromString?) are the right things to use here and how to use them, but I'm really struggling to understand where to go after a couple days of reading Apple's documentation, Stack Overflow questions, playing with sample code, and tinkering with my own code.
Sorry if the question is too lengthy, I thought it may be more helpful to others looking for assistance in the future to see the full idea. (At least I know sometimes I'm lost with these question pages.)
I would be very grateful for any assistance,
Ryan
You can dynamically invoke a method using a selector. You could for example have a secondary array to calcNames with selector called calcSelectors:
SEL calcSelectors[] = (SEL[3]){
#selector(first:arg:),
#selector(second:arg:),
#selector(third:arg:)};
Calling the right method would then be as simple as:
[self performSelector:calcSelectors[calcIndex] withObject:arg1 withObject:arg2];
If you need more then 2 arguments, then you also need to mess a bit with a NSInvocation instance to setup the call.
Example 1:
NSString *method=[calcNames objectAtIndex:0];//here play with objectatindex
SEL s=NSSelectorFromString(method);
[self performSelector:s];
which will call this method
-(void)first{
NSLog(#"first");
}
-----------------------------------------
Example 2:
NSString *totalMethodName;
totalMethodName=#"vijay";
totalMethodName=[totalMethodName stringByAppendingString:#"With"];
totalMethodName=[totalMethodName stringByAppendingString:#"Apple"];
SEL s=NSSelectorFromString(totalMethodName);
[self performSelector:s];
will call
-(void)vijayWithApple{
NSLog(#"vijayWithApple called");
}
You can make use of NSInvocation to dynamically bind multiple arguments to a selector. Follow this post to learn it.
If you are going to use NSInvocation you have to define your methods in the objective-C way something like the following.
- (double)firstCalcWithInput1:(double)input1 input2:(double)input2 andInput3:(double)input3;
- (double)secondCalcWithInput1:(double)input1 input2:(double)input2 andInput3:(double)input3;

String Help - Objective C

I'm trying to make an app that will respond to your command when inserted. So you type in any text in the first box and press enter. It will respond with a response in the 2nd field. I'm not sure how the coding is done here. I'm having trouble with the "if inputbox text = #"whatever", I'm pretty sure that is completely off. Here is the code I have so far (not iphone sdk):
#import "HeliosControl.h"
#implementation HeliosControl
- (IBAction)quitButton:(NSButton *)sender {
}
- (IBAction)sendButton:(NSButton *)sender {
if (inputBox *********) // <------ What do I put in for the asterisks?
{
[outputBox setStringValue:#"Welcome to the SYSTEM"];
}
else
{
[outputBox setStringValue:#"I do not understand your command."];
}
}
#end
BTW I'm a complete noob since I started Objective-C like a week ago.
Second Question:
This is a very simple one, but what would be the coding for closing an application? This is for my quit button.
You want if ([[inputBox stringValue] isEqualToString:#"whatever"]) (assuming inputBox is an NSTextField — otherwise, use the appropriate method for that class to get a string out of it).
Oh, and you can quit the application with [NSApp terminate:self].
Chuck's answer is spot on, but I thought it worth expanding on why you've had problems. There are a number of mistakes in your line:
"if inputbox text = #"whatever"
a) In Objective C you have to use == to check if x is equal to y. So the if statement would be:
if (myFirstVariable == mySecondVariable) { // Do something }
b) A string variable is actually a more complicated thing than a variable just holding a number. That variable's value will actually be the memory address where it is stored. Also, you will usually actually only be using a pointer (denoted by the * when you declare a variable) to the variable.
This means that if you type the following:
if (myFirstVariable == #"Some text")
or
if (myFirstStringVariable == mySecondStringVariable)
Then you're actually only checking for whether they both point to the same bit of memory! Not whether the text is the same. This is why as Chuck explained you need to use the [isEqualToString] method.
Hope that helps!