I have a form that once a user submits, it should reload the view (but change a few things).
On this form there is a UIPickerview (_tripPicker) that has 2 locations a starting location and an end location (2 components to the pickerview).
I have it saving to the appropriate database and all that - but when it reloads (when the user clicks save) I want the pickerview to 'reset', and the first location (begSchool), to match the users second location (endSchool) that they just saved to coredata.
For example: Lets say user went from PointB to pointC (component 0 & 1 respectively in the pickerview); when they click save, I would like component 0 to display "PointC" and for the second component to just display the list of points to go to (resetting it to how it originally loads).
I've attempted to try and do some of this matching strings, but I'm running into issues with it.
Here is the logic where I do this:
//Save the data & reload View
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
//Reset the pickerview **********THIS LOGIC NEEDS WORK**********
//Check to see if there is previous UserMiles entered - if so, set beg_school to appropriate name
// Get the local context
NSArray *tripsSorted = [UserMiles MR_findAllSortedBy:#"driven_date" ascending:NO];
if (!tripsSorted || !tripsSorted.count){
//if no previous trips have been entered - set the school list to default
begSchoolLabel.text = [_schoolArray1 objectAtIndex:[_tripPicker selectedRowInComponent:0]];
} else {
UserMiles *lastTrip = [tripsSorted objectAtIndex:0];
NSString *preValue = lastTrip.end_school;
begSchoolLabel.text = preValue;
NSUInteger *currentIndex = [_schoolArray1 indexOfObject:preValue]; //Error/warning that incompatible integer to point conversion
[_tripPicker selectRow:currentIndex inComponent:0 animated:YES]; //Error/warning here that incompatible point to integer conversion
NSLog(#"LastTrip.endSchool = %#", lastTrip.end_school);
}
//Set end school labels for the second component in the picker
endSchoolLabel.text = [_schoolArray2 objectAtIndex:[_tripPicker selectedRowInComponent:1]];
NSLog (#"saveInBackground: finished!");
}];
[self.view setNeedsDisplay];
lastTrip.end_school gets me the appropriate name of the school from component 1 of the pickerview, I just need to figure out how to match that with the appropriate value from the array that is loading the pickerview and make it selected in the pickerview. The text currently displays the appropriate name, but the pickerview does not show any change.
Please let me know if I need to clarify or what other code you need to see - thanks in advance.
I was able to solve this by first finding the indexValue in the array by matching the string against the Objects in the array.
I ended up with this:
//Save the data & reload View
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
//Reset the pickerview **********THIS LOGIC NEEDS WORK**********
//Check to see if there is previous UserMiles entered - if so, set beg_school to appropriate name
// Get the local context
NSArray *tripsSorted = [UserMiles MR_findAllSortedBy:#"driven_date" ascending:NO];
if (!tripsSorted || !tripsSorted.count){
//if no previous trips have been entered - set the school list to default
begSchoolLabel.text = [_schoolArray1 objectAtIndex:[_tripPicker selectedRowInComponent:0]];
} else {
UserMiles *lastTrip = [tripsSorted lastObject];
NSString *preValue = lastTrip.end_school;
begSchoolLabel.text = preValue;
int indexValue = [_schoolArray1 indexOfObject:preValue]; //Compares the preValue string to the strings in the array and finds the indexValue of the right match
[_tripPicker selectRow:indexValue inComponent:0 animated:YES]; //Sets the picker to the appropriate value
NSLog(#"LastTrip.endSchool = %#", lastTrip.end_school);
}
//Set end school labels for the second component in the picker
endSchoolLabel.text = [_schoolArray2 objectAtIndex:[_tripPicker selectedRowInComponent:1]];
NSLog (#"saveInBackground: finished!");
}];
[self.view setNeedsDisplay];
Related
I'm trying to make a game with 2 views, the first view has buttons which segues to another view. Depending on the segue identifier, it loads an image which the player has to guess.
I also have a an array which lists hints for the 4 images.
With the array, i made a button which shows the hints on the view, but the problem I have right now is that I don't know how to set the correct array to the image/puzzle.
A code that works right now is this:
if ([self.thePuzzle.name isEqual: #"lion"])
{
NSArray *hints = [lines[0] componentsSeparatedByString:#" "];
self.hintLabel.text = hints[0];
}
But after adding another line for the second image/puzzle, the app crashes.
2nd UPDATE: code that crashes
After entering this code
if ([self.thePuzzle.name isEqual: #"penguin"])
{
NSArray *hints = [lines[1] componentsSeparatedByString:#" "];
self.hintLabel.text = hints[1];
}
The hint button works for the 1st code, which has the lion picture, while the second part of the code, for the penguin pic, crashes when the Hint button is pressed.
3rd Update: Additional information
I made xcode access a file from the internet which contained the words for my array.
This is how i coded it.
[super viewDidLoad];
// Do any additional setup after loading the view.
self.imageView.image = [UIImage imageNamed:self.thePuzzle.imgFileName];
NSString *urlString = #"http://m.uploadedit.com/b032/1395295852132.txt";
NSString *contents = [TextFileManager readStringFromURL:urlString];
//parse contents
lines = [contents componentsSeparatedByString:#"\n"];
for( int i = 0; i < lines.count; i++)
{
NSString *line = lines[i];
NSLog(#"%d: %#", i, line);
}
I have a pickerview that displays an array of locations (2 components); below that are 2 UILabels (2 under each component).
When a user opens the app, the picker defaults to the first object in each array in the picker components and changes the label below to reflect that selection.
So it would look something like this:
|PickerComponent1|PickerComponent2|
| Label 1 | Label 2 |
It displays the labels correctly when [viewDidLoad] is called. The labels changed to the appropriate names.
I created an instance method - but I can't pass the text value of the labels to that method.
The log displays (null) and it's coming back as empty.
Any ideas on how I can pass that label text to the method appropriately?
*edit: if I put that code that assigned label1 and the NSLog line into the viewDidLoad method it prints out the label text appropriately. When I put it into the method it does not.
My viewDidLoad in my .m file:
- (void)viewDidLoad
{
//set self as delegate for tripPicker
_tripPicker.delegate = self;
//Set size of tripPicker & datePicker
_tripPicker.transform = CGAffineTransformMakeScale(0.60, 0.60);
_datePicker.transform = CGAffineTransformMakeScale(0.60, 0.60);
//Call method to get array of school names (reusable)
MetaMiles *model = [MetaMiles schoolNameList];
_schoolArray1 = (NSArray *)model;
_schoolArray2 = (NSArray *)model;
//Set date to current date
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"MM/dd/yyyy"];
_dateLabel.text = [NSString stringWithFormat:#"Date of trip: %#",[dateFormatter stringFromDate:self.datePicker.date ]];
//Set selector method for datePicker so on the value change it updates the date
[self.datePicker addTarget:self action:#selector(updateLabelForDate:) forControlEvents:UIControlEventValueChanged];
[super viewDidLoad];
//Set labels to be appropriate schools
begSchoolLabel.text = [_schoolArray1 objectAtIndex:[_tripPicker selectedRowInComponent:0]];
endSchoolLabel.text = [_schoolArray2 objectAtIndex:[_tripPicker selectedRowInComponent:1]];
//Update the Mileage indicator to display miles between currently selected values
ML54AddMilesViewController *milesObject = [[ML54AddMilesViewController alloc]init];
NSArray *currentMiles = [milesObject getMileage];
NSLog(#"Current Miles first run: %#",currentMiles);
}
My getMileage method:
- (NSArray *)getMileage {
//Update the Mileage indicator to display miles between currently selected values
NSString *begSchool = begSchoolLabel.text;
NSLog(#"FIRE THIS OFF : %#",begSchool);
NSString *endSchool = endSchoolLabel.text;
NSPredicate *milesFilter = [NSPredicate predicateWithFormat:#"beg_school=%# AND end_school=%#", begSchool, endSchool];
NSArray *resultMiles = [MetaMiles MR_findAllWithPredicate:milesFilter];
if (!resultMiles || ![resultMiles count]) {
NSLog(#"Empty Array");
} else {
NSLog(#"Our array is: %#", [resultMiles objectAtIndex:0]);}
return resultMiles;
}
What I ended up doing was instead of using the label to get the text - I just had it nab whatever the picker had chosen. The label updates appropriately but for some reason I couldn't pass it between methods - this other way I was able to do that.
NSString* digit = [sender currentTitle];
if (self.userIsInTheMiddleOfEnteringANumber){
NSString* currentDisplayText = [[self display]text];
NSString* newDisplayText = [currentDisplayText stringByAppendingString:digit];
self.display.text = newDisplayText;
I´ll try and explain my problem as good as I can. This line of code here takes the digit from a selection of buttons, saves it no the string "digit". "currentDisplayText"takes the digit displayed in a label. Then these two strings are appended and sent to the "display" (label)
But there is also an enter button. Which clears the display (so user can enter new number ) this is a calculator btw!
- (IBAction)enterPressed{
[self.brain pushOperand:[self.display.text doubleValue]];
self.userIsInTheMiddleOfEnteringANumber = NO;
What I want is to display a "history" label that displays all the numbers entered - I have not quite understood how I get the string I save the "history" too, to not reset like the display does. This might be bad exlained by me, but any hints are appreciated. I am still learning objective-c...
If I understood you correctly, you want to save the number after pressing the enter button. For this you need to add an attribute of type NSMutableArray to your class. Then in the method do:
- (IBAction)enterPressed {
[myHistoryArrayAttrib addObject: self.display.text];
[self.brain pushOperand:[self.display.text doubleValue]];
self.userIsInTheMiddleOfEnteringANumber = NO;
//after this you can clear your display
self.display.text = nil;
}
That's it.
I did not understander you very well , but one thing I am sure , if you want save your data (not very large) , you should use NSUserDeafult . use - (void)setObject:(id)anObject forKey:(id)aKey;to save the data.
You want to svae the history , if you want to save the lastest history , you could use - (NSString *)stringForKey:(NSString *)defaultName; to get the string which you save. and if you want to save the whole history , you could use - (NSArray *)arrayForKey:(NSString *)defaultName; to get the array which you save.
give an eg. how to save a string
if([[NSUserDefaults standardUserDefaults] stringForKey:theKey] == nil)
{
NSString *defaultValue = [NSString stringWithString:theStringYouWantedSave];
NSDictionary *saveDict = [NSDictionary dictionaryWithObject:defaultValue forKey:theKey];
[[NSUserDefaults standardUserDefaults] registerDefaults:saveDict];
}
else
{
[[NSUserDefaults standardUserDefaults] setObject:theStringYouWantedSave forKey:theKey];
}
and get like this
if([[NSUserDefaults standardUserDefaults] stringForKey:theKey]!=nil)
{
yourHistoryString = [[NSUserDefaults standardUserDefaults] stringForKey:theKey];
}
I have a multi-sectioin UITableView with different kinds of controls throughout various rows (multi-select checkboxes, single-select checkboxes, text inputs, text areas etc.). Each row could have a different data type (string, integer, date etc) and the number of rows and location are dynamic so you can't always depend on section X row Y being a certain control.
My question is what is the best way to save the data input into these fields for use in the view, grabbing the right data to show what was entered into that field when calling cellForRowAtIndexPath.
Note that I am NOT asking how to save this data persistently, I'm using CoreData for that, the question is just how to temporarily save the data while interacting with the view, so that you have it in an NSMutableArray or NSMutableDictionary ready to be saved with CoreData when the user touches the "Save" button, or completely discarded if they press "Cancel".
Currently I'm trying to implement a dictionary but it seems somewhat kludgy and I often get one row's data showing up in another row.
Here is my current method for saving the form data. It's using a name from the arguments along with a counter variable used for the view as a whole. The counter variable is also used as the tag integer for the control.
-(id)documentField:(UIView *)view withKey:(NSString *)key andValue:(id)value{
NSInteger foundTag = -1;
NSLog(#"searching dictionary for key: %#", key);
for(NSString *existingKey in fieldValues){
NSArray *keyParts = [existingKey componentsSeparatedByString:#"~"];
if( [[keyParts objectAtIndex:0] isEqualToString:key] )
{
foundTag = [[keyParts objectAtIndex:1] intValue];
NSLog(#"found key: %#, it's tag is: %d", [keyParts objectAtIndex:0], foundTag);
break;
}//end if
else{
//NSLog(#"no match: %# != %#", (NSString *)[keyParts objectAtIndex:0], key);
}
}//end for
//if we haven't tagged this element yet
//set the tag
if (foundTag == -1) {
view.tag = fieldValueCounter;
foundTag = fieldValueCounter;
fieldValueCounter++;
}//end if
NSString *fieldKey = [NSString stringWithFormat:#"%#~%d", key, foundTag];
if( ! [fieldValues objectForKey:fieldKey] ){
[fieldValues setObject:((value)? value : #"") forKey:fieldKey];
}
NSLog(#"returning fieldValue: %# = %#", fieldKey, [fieldValues objectForKey:fieldKey]);
return [fieldValues objectForKey:fieldKey];
}//end documentField:withKey:andValue:
And here is how it is being used.
((UTVCellTextField *)cell).textLabel.text = #"Door Location:";
((UTVCellTextField *)cell).textField.text = [self documentField:((UTVCellTextField *)cell).textField withKey:#"door.door_location" andValue:door.door_location];
((UTVCellTextField *)cell).textField.delegate = self;
I'm working on a roguelike using Objective-C/Cocoa to learn more. I've gotten most of the basic functionality out of the way, but I still have one problem I've been trying to figure out.
Here's a breakdown of the process:
First, the map is loaded:
NSString* mapPath = [[NSBundle mainBundle] pathForResource:mapFileName ofType:mapFileType];
NSURL* mapURL = [NSURL fileURLWithPath: mapPath];
currentMap_ = [[Map alloc] initWithContentsOfURL: mapURL];
worldArray = [[NSMutableArray alloc] init];
itemArray = [[NSMutableArray alloc] init];
[self populateMap];
return;
Then, in the populateMap function, it goes through each cell of the loaded map, using NSPoints and a loop, and creates objects based on the data from the map in WorldArray. For items, normal floor is put in where the item is, and an item is then made in itemArray. Both arrays are 30x30, as determined by the height of the map.
Here is the populateMap code:
- (void)populateMap
{
NSPoint location;
for ( location.y = 0; location.y < [currentMap_ height]; location.y++ )
{
for ( location.x = 0; location.x < [currentMap_ width]; location.x++ )
{
char mapData = [currentMap_ dataAtLocation: location];
for ( GameObject *thisObject in worldDictionary )
{
//NSLog(#"char: <%c>", [thisObject single]);
if ( mapData == [thisObject single])
{
NSString* world = [thisObject className];
//NSLog(#"(%#) object created",thisObject);
[self spawnObject:world atLocation:location];
}
}
for ( Item *thisObject in itemDictionary )
{
//NSLog(#"char: <%c>", [thisObject single]);
if ( mapData == [thisObject single] )
{
NSString* item = [thisObject className];
NSString* floor = [NormalFloor className];
//NSLog(#"(%#) object created",thisObject);
[self spawnItem:item atLocation:location];
[self spawnObject:floor atLocation:location];
}
}
if ( mapData == '1'
&& [player_ stepsTaken] <= 0)
{
//NSLog(#"player spawned at (%f, %f)",location.x,location.y);
player_ = [[Player alloc] initAtLocation: location];
}
if ( mapData == '1' )
{
//NSLog(#"floor created at (%f, %f)",location.x,location.y);
[worldArray addObject:[[NormalFloor alloc] initAtLocation: location]];
}
}
}
[self setNeedsDisplay:YES];
}
This is what is called when things are spawned:
- (void)spawnObject: (NSString*) object atLocation: (NSPoint) location
{
//NSLog(#"(%#) object created",thisObject);
[worldArray addObject:[[NSClassFromString(object) alloc] initAtLocation: location]];
}
- (void)spawnItem: (NSString*) item atLocation: (NSPoint) location
{
//NSLog(#"(%#) object created",thisObject);
[itemArray addObject:[[NSClassFromString(item) alloc] initAtLocation: location]];
}
worldArray and itemArray are what the game works on from that moment onwards, including the drawing. The player is inside of worldArray as well. I'm considering splitting the player into another array of characterArray, to make it easier when I add things like monsters in the not so distant future.
Now, when I load a new level, I had first considered methods like saving them to data and loading them later, or some sort of savestate function. Then I came to the realization that I would need to be able to get to everything at the same time, because things can still happen outside of the player's current scope, including being chased by monsters for multiple floors, and random teleports. So basically, I need to figure out a good way to store worldArray and itemArray in a way that I will be able to have levels of them, starting from 0 and going onward. I do need a savestate function, but there's no point touching that until I have this done, as you shouldn't actually be allowed to save your game in roguelikes.
So to reiterate, I need to have one set of these arrays per level, and I need to store them in a way that is easy for me to use. A system of numbers going from 0-upward are fine, but if I could use something more descriptive like a map name, that would be much better in the long run.
I've figured out my problem, I'm using an NSMutableDictionary for each and storing them with the keys that correspond to each level. Works like a charm. Bigger problems elsewhere now.
I figured it out, I'm using NSMutableDictionaries, one for each array (objects, items, eventually characters). They're stored using the name of the level. Works like a charm.