How to store value in NSMutableArray from ViewControllers - ios

I'm tying to solve my problem which is, i don't know how to store value from (for ex) 4 viewControllers and keep it in the last one. It should be like the scorecard, in first quarter I earned 4pt (and write it in TextField), in second quarter 5pt etc. In the last one it should be summed and sorted etc.
i stared from the last ViewController called it Result, another four called first, second etc.
In Result i created
#property(strong, nonatomic) NSMutableArray *array;
first, second etc inherits array from result and for First I created:
-(void) prepereForSegue:(UIStoryboardSegue*)segue sender :(id)sender
{
if ([segue.identifier isEqualToString:#"id1"]) {
NSString *str1 = [_firstResult text];
Result *Result1 = [segue destinationViewController];
Result1.array = [[NSMutableArray alloc]init];
[Result1.array addObject:str1];
}
}
for second:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"id2"]) {
NSString *str2 = [_SecondResult text];
Result *Result1 = [segue destinationViewController];
Result1.array = [[NSMutableArray alloc]init];
[Result1.array addObject:str2];
}
}
When I run the project in array is just the last score from fourth quarter.
I think that i shouldn't alloc and init NSMutableArray in each viewController but i don't know how make it work..
Please Help me.
Appreciate!

Yup, you are, every time creating a new array which have its current and single object.
Create a shared object and call that array to save and fetch values.
Or just create a array in appdelegate.

Each time you are creating a new array that's why array contains only last value. create an array in appDelegate or use shared object to save the results.

Related

Using Text Field to add String to NSMutableArray

I am looking to get an NSString value from a Text Field and add it to an array, I want to build an array with many strings in it ex:
[hello, goodbye, too soon].
This is my current solution:
- (IBAction)submitButton:(id)sender {
NSMutableArray *wordArray = [[NSMutableArray alloc] init];
NSString *input = textField.text;
[wordArray insertObject:input atIndex:arrayIndex];
arrayIndex++;
}
This works for the first item in the array, but when I press submit again it reinitializes.My issue is how do I initialize the NSMutableArray to use in the button function, without having it in there so that it doesn't initialize every time. Thank you
Your are using a local array that disappears as soon as the submitButton method is finished.
Make your wordArray an instance variable and initialize it once in viewDidLoad. Then in your submitButton: method (and any others), you reference the instance variable instead of creating local arrays.
Honey's answer is almost, but not, correct.
Your code uses a local variable in your submitButton method, and creates a new, empty array each time the method gets called. Both of those things are wrong.
Honey's answer has you create a different local variable in viewDidLoad. That's also wrong.
You need to make wordArray an instance variable or property of your class. If you class is called ViewController, say, it might look like this
#interface ViewController: UIViewController;
#property (nonatomic, strong) NSMutableArray *wordArray
...
#end
And then initialize it in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.wordArray = [[NSMutableArray alloc] init];
}
Then in the rest of your program refer to self.wordArray, the property.
Here's the solution,
#implementation ViewController{
NSMutableArray *_wordArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
_wordArray = [[NSMutableArray alloc] init];
}
- (IBAction)submitButton:(id)sender {
NSString *input = textField.text;
[wordArray addObject:input];
}
You was re init the array each time you make the action, which will let you always save the last value of the textfield.
but this creates an array as global variable so that you can add all the values entered in textfield.
Hope this help you :)

How can a picture array within another array from a set of arrays be used with a swipe gesture?

Complicated wording for something that is relatively simple. Where is an array of pictures defined if, it itself is a particular array item?
I have a set of arrays which are passed through a tableView to a DetailedViewController. One of which is images. On this DetailedView I would like to be able to implement a swipe gesture on a UIImageView so I can swipe through what essentially is an array of images inside of a particular array item.
PseudoCode:
Array 1:
array1-string1
array1-string2
array1-string3
Array 2:
array2-string1
array2-string2
array3-string3
Array 3:
array3-picture1
array3-picture2
array3-picture3
Each array stores a different set of data corresponding to the position in the array. eg: Array1 is all the names, Array2 is all the descriptions, Array3 is all the pictures.
The detailedView displays one set of data. eg. array1-string1, array2-string1, array3-picture1.
Correct me if i'm wrong but in order to use the swipe gesture (for a particular set of data) I need an array of images as the array3-picture1 item.
Would I specify this array when I initially declare all the arrays, in order for it to be hooked to an IBAction on the final detailedViewController, keeping in mind that this is called on a specific segue to the tableView.
OR
Simply declare the array as just an array at the start and specify the values of it somewhere else.
Sorry if that makes no sense, but dealing with this has been doing my head in!
I'd begin by considering this input data as not yet in object form. You can create an NSObject subclass or a dictionary grouping related data. For example (using dictionary):
NSMutableArray *objects = [NSMutableArray array];
NSAssert(array1.count == array2.count == array3.count, #"arrays must be of equal length");
NSInteger count = array1.count;
for (NSInteger i=0; i<count; i++) {
NSDictionary *d = #{ #"name": array1[i], #"description": array2[i], #"image": array3[i] };
[objects addObject:d];
}
This objects array can be the model for your table view, maybe presenting the names at the top level. Upon selection, segue to a detail view, passing data like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"DetailSegue"]) {
MyDetailViewController *vc = segue.destinationViewController;
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
vc.object = self.objects[selectedIndexPath.row];
}
}
Then the detail vc does it's business by referring to the public property which I assumed in the above to be called object. e.g.:
self.descriptionLabel.text = self.object[#"description"];

Update Label of a Custom Subclass of UITableViewCell after navigation return?

I am trying to update the score of one of the labels on my custom cell after returning from a push navigation.
In my parent UITableViewController I have the code:
In ViewDidLoad
//These are mutable strings
self.disciplineScoreString1 = [NSMutableString stringWithFormat:#""];
self.disciplineScoreString2 = [NSMutableString stringWithFormat:#""];
self.disciplineScoreString3 = [NSMutableString stringWithFormat:#""];
self.disciplineScoreArray = [[NSMutableArray alloc] init];
[self.disciplineScoreArray addObject:self.disciplineScoreString1];
[self.disciplineScoreArray addObject:self.disciplineScoreString2];
[self.disciplineScoreArray addObject:self.disciplineScoreString3];
So far so good.
In cellForRowAtIndexPath
//this is the custom subclass of UITableViewCell
DayTableViewCell *cell = (DayTableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//this is the custom label
cell.disciplineScoreLabel.text = [self.disciplineScoreArray objectAtIndex:indexPath.row];
return cell;
Still so far so good. Right now the label in each of the 3 cells is blank.
I now segue to a UIViewController from the first cell and I return from the child UIViewController successfully setting the string value of self.disciplineScoreString1 to #"10"which I NSLog'ged in the parent UITableViewController.
How do I update the label for the first cell now? I have tried reload data in ViewWillAppear but its not working.
Thankyou
EDIT
This is the code in the Child ViewController
In viewWillDisappear:
[super viewWillDisappear:animated];
[self calculateDisciplineScore];
NSInteger currentVCIndex = [self.navigationController.viewControllers indexOfObject:self.navigationController.topViewController];
DisciplineTableViewController *parent = (DisciplineTableViewController *)[self.navigationController.viewControllers objectAtIndex:currentVCIndex];
parent.disciplineScoreString1 = self.disciplineScoreText;
You must be changing the string, instead of modifying it... consider this example
NSMutableArray *array = [NSMutableArray array];
NSMutableString *disciplineScoreString1 = [NSMutableString stringWithFormat:#"original string"];
[array addObject:disciplineScoreString1];
[disciplineScoreString1 appendString:#" hello"]; // OK.. you're modifying the original string
NSLog(#"%#", [array objectAtIndex:0]);
disciplineScoreString1 = [NSMutableString stringWithFormat:#"new string"]; // WRONG!!
NSLog(#"%#", [array objectAtIndex:0]);
The ouput is:
2014-02-15 06:36:46.693 Hello[19493:903] original string hello
2014-02-15 06:36:46.694 Hello[19493:903] original string hello
The second example is wrong because you're creating a new string, and the object in the array is still pointing to the old original string.
EDIT:
// try this
[parent.disciplineScoreString1 replaceCharactersInRange:NSMakeRange(0, parent.disciplineScoreString1.length) withString:self.disciplineScoreText];
// instead of
parent.disciplineScoreString1 = self.disciplineScoreText;
Your current approach is quite rigid and not very standard. You would normally set up some kind of delegate to pass data from a child to a parent. It is very rarely correct that a child should know how to reach into the parent's innards and change it's data.
I would personally start with something like this
#interface ChildViewController : UIViewController
#property (nonatomic, copy) void (^onCompletion)(ChildViewController *viewController, NSString *disciplineText);
#end
Now I'm assuming you are dismissing by just calling [self.navigationController popViewControllerAnimated:YES] from within the child? This is a little odd as it means that the childViewController can now only ever be presented in a navigationController, this makes it less reusable.
What I would do is at the point where you normally call popViewControllerAnimated: I would call the completion instead
if (self.onCompletion) {
self.onCompletion(self, self.disciplineText);
}
Now the object who provides the onCompletion can decide how this controller get's removed and it's told about the data that we finished with, which enabled the controller to do what it wants with it.
In your case the parent controller would provide the completion as it knows how the child is presented so it will know how to dismiss it. It also know that it may want to do something with the data the child finished with
// Where you present the child
childViewController.disciplineText = self.self.disciplineScoreArray[index];
__weak __typeof(self) weakSelf = self;
childViewController.onCompletion = ^(ChildViewController *viewController, NSString *disciplineText){
weakSelf.disciplineScoreArray replaceObjectAtIndex:index withObject:disciplineText];
[self.navigationController popViewControllerAnimated:YES];
[weakSelf.tableView reloadRowsAtIndexPaths:#[ [NSIndexPath indexPathForRow:index inSection:0] ]
withRowAnimation:UITableViewRowAnimationFade];
};

Adding to a NSMutableArray

I can't find an obvious answer this. I'm trying to add things to an array, so I assume I need to use an NSMutableArray
I have a ViewController (CVDownload) and and a TableViewController(CVTableViewController). The NSMutableArray is declared in CVTableViewController.h
#property (strong, nonatomic) NSMutableArray *cvFiles;
I then try to add a string to it in the CVDownload.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
CVTableViewController *controller = (CVTableViewController *)segue.destinationViewController;
[controller.cvFiles addObject:(#"sdsd")];
}
That doesn't work. I'm assuming because I haven't initialised the array. I've tried initialising the array in CVDownload.m
NSMutableArray *cvFiles = [NSMutableArray array];
but that doesn't work either. In debug, the array is still nil. I don't understand where I'm going wrong.
Basically, my goal is to have an array in CVTableViewController that is used to populate a Table, and I want to be able to add to the array in CVDownload. Is there something I'm missing? Does NSArray have a similar method to NSString's stringByAppendingString?
In the init method of CVTableViewController write this:
self.cvFiles = [NSMutableArray new];
CVTableViewController *controller = (CVTableViewController *)segue.destinationViewController;
if(nil == controller.cvFiles)
{
controller.cvFiles = [[NSMutableArray alloc] init];
}
[controller.cvFiles addObject:(#"sdsd")];
Where are you initializing the array? Are you sure that it is created before prepareForSegue: is called?
// Edit: I ask because, as confirmed in the comments, the array is initialized after prepareForSegue: is called. The fix, as mentioned there, is to initialize the array in -awakeFromNib instead of -viewDidLoad.

NSArray losing value at the end of method

I have a project I am working on, to learn some more about JSON and restkit. It all is working great, however I am having trouble with an array losing it's values.
This is the last method that is executed in my network request.
SHRetrieveStoresWS.m
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObjects:(NSArray *)objects
{
self.stores = [[NSArray alloc] initWithArray:objects];
StoresViewController *viewController = [[StoresViewController alloc] init];
[viewController didLoadObjects:objects];
for (Store *aStore in stores) {
NSLog(#"%#", [aStore longName]);
}
}
Which calls this method in my view controller.
StoresViewController.m
#property (strong, nonatomic) NSArray *data;
- (void)didLoadObjects:(NSArray *)aArray
{
NSLog(#"%d", aArray.count);
self.data = [[NSArray alloc] initWithArray:aArray];
NSLog(#"%d", data.count);
[self.tableView reloadData];
}
The values are correct when I ask for the values within this method, but the array shows 0 objects immediately afterwards. Am I missing something here?
I am later checking the value with this method.
- (IBAction)pushMe:(id)sender
{
NSLog(#"Data: %d", self.data.count);
}
You should pass the data in the segue...
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString: #"MY_IDENTIFIER"]){
StoresViewController *viewController = segue.destinationViewController;
[viewController didLoadObjects: objects];
}
}
That should work for you! Just change MY_IDENTIFIER to whatever the identifier of your segue is.
StoresViewController is initialised as a local variable which is only accessible in the method that it was declared (aka objectLoader). After objectLoader has completed, the local variable is no longer valid.
The problem is most likely that you're creating multiple instances of StoresViewController instead of giving your network controller a reference to the original instance.
You can demonstrate it to yourself by printing out self in -viewDidLoad and again in didLoadObjects:. You'll see that the pointer addresses are different.
This line is the culprit:
StoresViewController *viewController = [[StoresViewController alloc] init];
Instead of instantiating StoresViewController again, add a property to your SHRetrieveStoresWS class and use it to hold a reference to your view controller.
#property (strong) StoresViewController *viewController;
You'll need to set that property before -didLoadObjects: is invoked.

Resources