Determine one column value from another column in pickerview - ios

I am working on a picker view with 3 columns. I want to determine the 3rd column value from the second column. Here is part of my code
- (void)viewDidLoad {
[super viewDidLoad];
Number=#[#"Trans",#"1st",#"2nd",#"3rd",#"4th",#"5th",#"6th",#"7th",#"8th",#"9th",#"10th",#"11th",#"12th"];
Season=#[#"Spring",#"Summer",#"Fall"];
Course=#[#"CHEM1100 General Chem I",#"CHEM2100 General Chem II",#"CHEM3511 Org Chem",#"CHEM3521 Org Chem II"];
// Course=#[#"Summer1",#"Summer2",#"Summer3"];
Course = [Course sortedArrayUsingSelector:#selector(compare:)];
Number =[Number sortedArrayUsingSelector:#selector(compare:)];
Season =[Season sortedArrayUsingSelector:#selector(compare:)];
}
Here is my question, how can I achieve the goal like
if (Season==#"Spring")
Course= #[#"CHEM1100 General Chem I",#"CHEM2100 General Chem II",#"CHEM3511 Org Chem",#"CHEM3521 Org Chem II"];
else if (Season==#"Summer")
Course=#[#"Summer1",#"Summer2",#"Summer3"];
Sorry, I don't know what method to use to complete the code. Any idea please?
To show the column value, I use the following code:
- (IBAction)addCourse:(UIButton *)sender {
NSInteger numRow=[picker selectedRowInComponent:kNumComponent];//0=1st,1=2nd,etc
NSInteger SeaRow=[picker selectedRowInComponent:kSeaComponent];//0=fall,1=spring,2=summer
NSInteger CourseRow=[picker selectedRowInComponent:kCourseComponent];
NSString *num=Number[numRow];
NSString *season=Season[SeaRow];
NSString *course=Course[CourseRow];
NSString *msg=[[NSString alloc ]initWithFormat:#"%# ",course];
_courseLabel.text=[msg substringToIndex:8];
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
if (component==kNumComponent)
return [Number count];
else if(component==kSeaComponent)
return [Season count];
else return [Course count];
}

According to the documentation, you must provide your UIPickerView with a datasource and a delegate. The datasource tells the view how many components and rows there are, while the delegate tells it the content of the components row. Let us suppose that you implement titleForRow: in your delegate. Since this is going to change based on a selection, you will need to do two things: (i) make sure your delegate object knows which selection was made (e.g. #"Spring") and (ii) you will then need to call the UIPickerView reloadComponent: method so that your delegate's titleForRow: method will be called.
Example: suppose your action method is componentSelected:
-(void)componentSelected:(id)sender
{
NSInteger row = [myPicker selectedRowInComponent:seasonComponent];
myDelegate.season = row;
[myPicker reloadComponent:courseComponent];
}
By the way, it is worth getting into the habit of being very careful with "=", "==", isEqualToString: etc. to avoid bugs. Your question has several basic syntactical errors. The line
if(season = #"spring")
should be
if([season isEqualToString:#"spring"]);
not just because "=" is assignment, but because "==" makes no sense if one of the arguments is a literal (it is essentially pointer comparison). isEqualToString will compare the target string with the argument string.

Related

Dot syntax and square brackets

I am doing a tuturial on Lynda.com for objective-c, and ran accross this example code. This is a part of the ViewController.m file. The idea behind the exercise was to create a picker object with custom elements in it.
The following code works just fine and gives me a picker with "happy" and "sad" as the options:
#implementation ViewController
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [[self moods] count];
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return self.moods[row];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.moods = #[#"happy",#"sad"];
}
However, I prefer square brackets to dot syntax and, as you can see I experimented in a few different places with it. Thereturn [[self moods] count was written as return [self.moods count] in the tutorial, but I wanted to use square brackets to verify that it still worked and I understood what was going on, so I changed it and it worked just fine. HOWEVER, I have been trying to do the same thing with the self.moods = #[#"happy",#"sad"]; because I don't like how it looks. I tried:
[[self moods] initWithObjects: #"happy",#"sad", nil];
But I just got a blank picker and a warning "expression result unused". I tried putting _moods = before that expression, and still got a blank picker. What is wrong here?
The reason that [[self moods] initWithObjects: #"happy",#"sad", nil]; is not doing what you expect is due to a misunderstanding in what is happening with regards to dot syntax and how it relates to message sending using square brackets.
Dot syntax is the "syntactic sugar" and recommended way of accessing properties of classes, such as the mood property from your question. Dot syntax is simply a shorthand for accessors (setters / getters) in Objective-C. A quick example might help clear this up.
When dot syntax finds itself on the right hand side of an assignment operator OR as the receiver of a message, the getter method is invoked.
// These two are equivalent
NSArray *allMoods = self.moods
NSArray *allMoods = [self moods]
// These two are equivalent
NSUInteger count = [self.moods count];
NSUInteger count = [[self moods] count];
When dot syntax finds itself on the left hand side of an assignment operator, the setter method is invoked.
// These two are equivalent
self.moods = #[#"happy", #"sad"];
[self setMoods:#[#"happy", #"sad"];
Using dot syntax is not only a nice shorthand, it makes your intentions clearer and newcomers to your code immediately aware that moods is a property of your class.
Also, the reason that [[self moods] initWithObjects: #"happy",#"sad", nil]; is not valid is because -initWithObjects: is an initializer of NSArray that should be called immediately following +alloc. In the piece of code above, [self moods] is returning an NSArray that already exists or lazily instantiating one. For completeness, -initWithObjects should be used as follows:
NSArray *myArray = [[NSArray alloc] initWithObjects:#"happy", #"sad", nil];
I assume you declared #property (strong, nonatomic) NSArray *moods; in the interface since self.moods works.
Setter and getter methods setMoods and getMoods are created automatically.
Here's how the dot syntax boils down to
// These are equivalent
self.moods = #[#"happy",#"sad"];
[self setMoods:#[#"happy",#"sad"]]; // Literal declaration
[self setMoods:[[NSArray alloc] initWithObjects:#"happy",#"sad",nil]]; // Full declaration
This works because you were using the "literal" way of declaring an NSArray* which includes both "allocation" and "initialization".
- (instancetype)initWithObjects: is an instance method which should be called on an instance variable already allocated with alloc. You tried to initialize a variable which has never been allocated in memory.
An slightly cleaner alternative would be:
[self setMoods:[NSArray arrayWithObjects:#"happy",#"sad",nil]];
arrayWithObjects: include both allocation and initialization.
the [self moods] way of referencing it can only be used on the right hand side of an expression, it's calling the getter for the property. self.moods = ... is actually syntactic sugar for [self setMoods:...]
so try [self setMoods:#[#"happy",#"sad"]]
You'll want to read up on the #property declaration and how it "synthesizes" getter and setter methods. What you want to do is "set" the moods property:
[self setMoods: #[#"happy",#"sad"]];

Passing data from a UIPickerView back to its delegate

I have a UIPickerView inside a custom tableViewCell (subclassed). I'am able to populate it and get data back from it. More or less.
I have this method I implement in order to get info everytime some of the components changed:
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if (self.pickerDelegate !=nil &&[self.pickerDelegate conformsToProtocol:#protocol(PickerCellDelegate)]) {
if ([self.pickerDelegate respondsToSelector:#selector(somethingOnThePickerIsSelected:selectionArray:)]){
NSMutableArray *pepe;
for (int i=0; i<[[self.cellPickerInputDictionary objectForKey:#"components"] count]; i++) {
NSObject*foo=[[[self.cellPickerInputDictionary objectForKey:#"components"] objectAtIndex:i] objectAtIndex:[self.cellPicker selectedRowInComponent:i]];
[pepe addObject:foo];
NSLog (#"foo: %#", foo);
}
NSLog (#"pepe: %#", pepe);
[self.pickerDelegate somethingOnThePickerIsSelected:self selectionArray:pepe];
}
}
}
I have two components, but in order to make it "universal" (independent of a particular situation) I don't want to hard-write numbers here and there.
In the example shown, I don't understand why the NSLog shows correct for the variable foo but shows null for the NSMutableArray pepe.
Any ideas? Thanks in advance.
You are not allocating your mutable array pepe.
NSMutableArray *pepe=[[NSMutableArray alloc]init];
In fact, you can do that on your init method, and declare pepe as property

sorting through an array - objective C/iOS

so I'm creating a contact list app and I'm storing everything into an NSMutableArray. I've managed to get add function working perfectly. But I'm struggling with the Previous/Next functions.
I can get it to go back one object in the array when pressing previous, but i Can't get it to go back any further? here's my code: I have two extra classes, PhoneBookEntry which is a subclass of the Person class. These classes contain three strings, Firstname,lastname and studentID
- (IBAction)addPerson:(id)sender {
PhonebookEntry *person = [[PhonebookEntry alloc] init];
NSLog(#"%#",self.firstName.text);
person.firstName = self.firstName.text;
person.lastName = self.lastName.text;
person.phoneNumber = self.phoneNumber.text;
[self.entries addObject:person];
Here's my Previous button:
int length;
length = [self.entries count];
if (length > 0) {
int index;
index = [self.entries count] - 1;
NSLog (#"%d the index is", index);
NSLog(#"object %#", [self.entries objectAtIndex:index]);
} else {
NSLog (#"No contacts have been entered. No");
}
//NSLog(#"%d is the length - 1 hopefully", length);
//NSLog (#"index at %d is ", length);
I've tried removing the - 1 here:
index = [self.entries count] - 1;
and changing then on the next line putting index--; but nothing seems to work. it just goes back once.
I understand that length is getting the amount of objects in the index, and then -1 but shouldnt i-- at the end of the count / - 1 keep removing it everytime its pressed??
Any ideas? Cheers
You're going to keep hitting the same index with that piece of code - you need to store the state somewhere. Who is going to hold onto what the current index is? With a good designed system the model should really take care of this.
You are best off storing the current index into an ivar and updating that every time the button is pressed.
#interface OKAClass ()
#property (nonatomic, assign) NSInteger currentIndex;
#end
//... initialise the property with a default value
self.currentIndex = [self.entries count] - 1;
//... when the button is pressed decrement the index (you might want some min / max validation or use modulus to loop over and start from the top again)
NSLog(#"%#", self.entries[self.currentIndex--]);

Is there anyway I can compare a String (which is a word) and a letter which is input by the user and receive an output as a BOOL

I'm new to IOS dev and am making simple programs this one is a hangman game.
I wanted to pick a random string from a plist file (completed).
I now want to compare the user input text (from a text field) and compare it to the string we have randomly picked from our plist.
Here is my code for MainViewController.m as it is a utility. Only the MainView is being used currently.
#import "MainViewController.h"
#import "WordListLoad.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize textField=_textField;
#synthesize button=_button;
#synthesize correct=_correct;
#synthesize UsedLetters=_UsedLetters;
#synthesize newgame=_newgame;
- (IBAction)newg:(id)sender
{
[self start];
}
- (void)start
{
NSMutableArray *swords = [[NSMutableArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"swords" ofType:#"plist"]];
NSLog(#"%#", swords);
NSInteger randomIndex = arc4random() % [swords count];
NSString *randomString = [swords objectAtIndex:randomIndex];
NSLog(#"%#", randomString);
}
This is where i would like to implement the checking
I have tried characterAtIndex and I can't seem to get it to work for hard coded placed in the string let along using a for statement to systematic check the string.
- (void)check: (NSString *) randomString;
{
//NSLogs to check if the values are being sent
NSLog(#"2 %#", self.textField.text);
}
- (IBAction)go:(id)sender
{
[self.textField resignFirstResponder];
NSLog(#"1 %#", self.textField.text);
[self check:(NSString *) self.textField];
_textField.text = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self start];
}
To compare 2 strings: [string1 equalsToString:string2]. This will return true if string1 is equal to string2. To get the string contained in a UITextfield: textfield.text.
Given that it's a hangman game, I assume you are trying to see if a single letter is contained by a given string - so equalsToString: wouldn't be what you want.
Instead, probably better to use rangeOfString:options:
if ([randomString rangeOfString:self.textfield.text options:NSCaseInsensitiveSearch].location != NSNotFound){
// Do stuff for when the letter was found
}
else {
// Do stuff for when the letter wasn't found
}
Also, as was pointed out by Patrick Goley, you need to make sure you're using the textfield.text value to get the string from it. Same with storing the initial word you'll be using as the hidden word.
There are also a couple of other minor code issues (semicolon in the function header, for example) that you'll need to clean up to have a functioning app.
Edit: Made the range of string call actually use the textfield's text, and do so case-insensitive (to prevent false returns when a user puts a capital letter when the word is lower case, or vice-versa). Also included link to documentation of NSString's rangeOfString:options:
For your check method you are sending the UITextfield itself, instead of its text string. Instead try:
[self check: self.textfield.text];
You'll also need to create an NSString property to save your random string from the plist, so you can later access to compare to the textfield string like so:
declare in the interface of the class:
#property (nonatomic,strong) NSString* randomString;
in the start method:
self.randomString = [swords objectAtIndex:randomIndex];
in the check method:
return [self.randomString isEqualToString:randomString];

NSMutableArray property initialization and updating

Suppose I have a #property that is an NSMutablearray that is to contain scores used by four objects. They will be initialized as zero and then updated during viewDidLoad and throughout operation of the app.
For some reason, I can't wrap my mind around what needs to be done, particularly at the declaration and initialization steps.
I believe this can be a private property.
#property (strong, nonatomic) NSMutableArray *scores;
#synthesize scores = _scores;
Then in viewDidLoad I try something like this but get an error. I just need help with syntax, I think. Or I'm missing something very basic.
self.scores = [[NSMutableArray alloc] initWithObjects:#0,#0,#0,#0,nil];
Is that an appropriate way to initialize it? Then how do I add (NSNumber *)updateValue to, say, the nth value?
Edit: I think I figured it out.
-(void)updateScoreForBase:(int)baseIndex byIncrement:(int)scoreAdjustmentAmount
{
int previousValue = [[self.scores objectAtIndex:baseIndex] intValue];
int updatedValue = previousValue + scoreAdjustmentAmount;
[_scores replaceObjectAtIndex:baseIndex withObject:[NSNumber numberWithInt:updatedValue]];
}
Is there a better way of doing this?
You are initializing in viewDidLoad, However you should do it in init.
These both are similar, and perfectly valid.
_scores = [[NSMutableArray alloc] initWithObjects:#0,#0,#0,#0,nil];
or,
self.scores=[[NSMutableArray alloc]initWithObjects:#0,#0,#0, nil];
Your last question... Then how do I add (NSNumber *)updateValue to, say, the nth value?
If you addObject: it will be added at last. You need to insertObject:atIndex: in your required index, and all following objects will shift to next indices.
NSInteger nthValue=12;
[_scores insertObject:updateValue atIndex:nthValue];
EDIT:
After your edit,
NSInteger previousValue = [[_scores objectAtIndex:baseIndex] integerValue];
NSInteger updatedValue = previousValue + scoreAdjustmentAmount;
[_scores replaceObjectAtIndex:baseIndex withObject:[NSNumber numberWithInt:updatedValue]];

Resources