NSMutableArray persistency while switching view controllers - ios

I've searched a lot and still couldn't find an answer to this...
I'm working on an iphone App (for college) in xcode 5.0 using storyboards.
I have a View Controller with a table view and everything works fine (data sources, delegate...). Items are stored in an array (call it "array1"). I have an ADD button which brings up a list of items which I want to add (if checked) to array1. I store the checked items in another array ("array2"). The thing is, when I pass array2 to the previous view controller I lose all data in array1 (it becomes nil).
The code I'm using to pass data from array2 to the VC is:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"updateFavoritesSegue"]) {
FavoritesViewController *targetVC = (FavoritesViewController*) segue.destinationViewController;
[targetVC updateFavorites:[self newFavoritesArray]];
}
}
The updateFavorites method is implemented as below.
-(void) updateFavorites:(NSArray *)newFavorites {
[self.favorites addObjectsFromArray:newFavorites];
[self.favoritesTableView reloadData];
}
Thank you very much for your help.

Why don't you just use some handler?
secondVC.h
#property (nonatomic, copy) void (^didFinishPickingItemsHandler)(NSArray *items);
then from the firstVC:
- (void)showSecondScreen {
MYSecondVC *secondVC = /* initialisation code here */
__weak MyFirstVC *self_ = self;
secondVC.didFinishPickingItemsHandler = ^(NSArray *items) {
/* update you data here with your array1 and received picked items */
[self.navigationController popViewControllerAnimated:YES];
};
[self.navigationController pushViewController:secondVC animated:YES];
}

Related

passing nesting through segue nil on init methods but valid on viewdidload

I have made a segue passing a string which tells the next view controller which instance to parse the CoreData for. The problem is, I am using some code that calls init methods and the sent string is not initialized when it is called. However, the segue is working when I display the string in the destination view controller's viewDidLoad
- (id)init
{
self = [super init];
if (self)
{
[self initFakeData];
}
return self;
}
When that initFakeData method is called it sets up a graph and needs the exercise to hold a valid value
- (void)initFakeData
{
NSString *myExercise=exercise; //returns nil
if (myExercise==nil)
{
myExercise=#"Default";
}
}
Meanwhile...
-(void)viewDidLoad{
NSString *myExercise=exercise; //returns value
}
exercise is a property that is initialized by the previous view controller in a tableview
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
if ([segue.identifier isEqualToString:#"showGraph"]) {
JBLineChartViewController *destViewController = segue.destinationViewController;
NSString *myExericse=[NSString stringWithFormat:#"%#", [[_exercises valueForKey:#"exercise"]objectAtIndex:indexPath.row]];
NSLog(#"%#",myExericse);
destViewController.exercise = myExericse;
}
}
The behaviour is correct because during init the exercise in JBLineChartViewController was not set. If you need the exercise attribute in the init method to set certain behaviour that have to be before viewDidLoad, my suggestion is to not use segue but do a designated initWithExercise and push the controller in code. Maybe like this:
- (IBAction)chartButtonPressed:(id)sender {
JBLineChartViewController *vc = [[ShopViewController alloc]initWithExercise:#"EXERCISE_STRING_HERE"];
[self showViewController:vc sender:self];
}
The new view controller is allocated and initialized before prepareForSegue is called. Anything you need to do with CoreData should be done in viewDidLoad. Or you can do it later, e.g. in viewWillAppear or viewDidAppear.

Passing Data between view Controller and a Table View Controller

I am trying to pass a string value namely,'_passedDataDate' from a viewController to a TableView Controller. And there in the TableViewController,I am trying to keep it in a array namely,'_dateArray'. while trying to do so, at first a nil object gets inserted and then the real object. how to avoid this nil value getting added?
Here is the code bellow,
- (void)viewDidLoad {
[super viewDidLoad];
_dateArray = [[NSMutableArray alloc] init];
_dateString = _passedDataDate;
if(_dateString){
[_dateArray addObject:_passedDataDate];
NSLog(#"Added Passed Data");
NSLog(#"%ld",[_dateArray count]);
}
else{
NSLog(#"No object Added");
NSLog(#"%ld",[_dateArray count]);
}
}
Output is as follow:
No object Added
0
Added Passed Data
1
Why No object Added is getting printed? I do not want it what shall Ido about it?
Also,I get the below warning,
Warning: Attempt to present on whose view is not in the window hierarchy!
Don't use Segue inside the button action.
Hide the segue
[self performSegueWithIdentifier:#"pass" sender:nil];
And try this :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString: #"pass"])
{
TableViewController *tableView = [segue destinationViewController];
tableView.passedDataDate = #"HAI";tableView.passedDataDestination = #"Hellio";
}
}

Pass informaion back to mother view

I'd like to pass some object from one view (number 2) to view number 1. View 1 triggers view 2 and before that in "prepareForSeque" I'm passing "self" to the second view and store it in variable "delegate". After some time I'd like to pass back new created object to view 1 and I'm trying to achieve it but I got an error that method is not visible for this interface. How to pass created object to the mother view triggering method?
When I declare #property someObject and synthetize it, it works ok using delegate. Is there another option or am I forced to use delegate?
Code:
- (IBAction)saveAndClose:(id)sender {
KwejkModel *mod = [[KwejkModel alloc] init];
((ViewController *)self.delegate).model = mod;
}
It works ok, but is there another option triggering method not using the property? Like this:
[((ViewController *)self.delegate) someMethod];
but here is an error.
Here is my code:
VIEW 1
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"addItemSeque"]) {
ScrollViewViewController *destViewController = segue.destinationViewController;
destViewController.delegate = self;
}
}
-(void) addNewPosition:(KwejkModel *)newKwejk
{
//for testing only this
[modelArray count];
}
VIEW 2:
- (IBAction)saveAndClose:(id)sender {
KwejkModel *mod = [[KwejkModel alloc] init];
// ((ViewController *)self.delegate).model = mod;
//it crashes here with error:-[NSPlaceholderString initWithString:]: nil argument' but it sees method from VIEW 1
[self.delegate addNewPosition:mod];
}
Try this link: Passing Data between View Controllers
Take a look at the first answer under Passing Data Back.

Thread1 exc_bad_access (code =2)... help me

i've been fixing this problem for a few days. but can't seem to get it..
help me out ..
let me explain my situation. Basically, i have navigation controller that contains table view controller and view controller. and i'm making simple phone book app.
And, i have a directory entry declared in extension class
#interface DetailViewController ()
#property DirectoryEntry *dirEntry;
#end
And, in table view, when you click the button it will transfer some data through segue
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DetailViewController *detailCV = [segue destinationViewController];
if ([segue.identifier isEqualToString:#"cellToDetail"]) {
[detailCV setDirEntry: [self.pbArray objectAtIndex:[self.tableView indexPathForSelectedRow].row]];
} else {
detailCV.dirEntry = nil;
}
//designate delegate !!!
detailCV.delegate = self;
}
My Problem occurs when it execute detailCV.dirEntry = nil; it will call my setter in viewController. it says EXC_BAD_ACCESS
-(void) setDirEntry:(DirectoryEntry *) dirEntry {
self.dirEntry = dirEntry;
}
Thank you in advance..
It's not an EXC_BAD_ACCESS so much as the OS killing your app for smashing the stack. This method is recursing infinitely:
-(void) setDirEntry:(DirectoryEntry *) dirEntry {
self.dirEntry = dirEntry;
}
Your use of dot notation expands to a setter which should make this more clear.
-(void) setDirEntry:(DirectoryEntry *) dirEntry {
[self setDirEntry:dirEntry];
}
Set the instance variable directly, or let the compiler handle it. Properties in class extensions are automatically synthesized.

How can I pass data from parent to child view?

I have a container view, which uses a storyboard embed segue to load an embedded static table view. The segue ID is 'CONTAINER'.
When I run the following code, the prepareForSegue never actually gets called so no data is passed from the parent to the child.
- (void)viewDidLoad {
[super viewDidLoad];
if ([sGender isEqualToString:#"MALE"]) {
containerGender = #"MALE";
if ([containerGender isEqualToString:#"MALE"]){
NSLog(#"MALE");
}else{
NSLog(#"BROKEN");
}
}
else if ([sGender isEqualToString:#"FEMALE"]) {
containerGender = #"FEMALE";
}
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"CONTAINER"]) {
if([containerGender isEqualToString:#"MALE"]) {
if ([containerGender isEqualToString:#"MALE"]){
NSLog(#"MALE");
}else{
NSLog(#"BROKEN");
}
SportTableViewController *tableView = segue.destinationViewController;
tableView.sportGender = #"MALE";
}
else if ([containerGender isEqualToString:#"FEMALE"]){
SportTableViewController *tableView = segue.destinationViewController;
tableView.sportGender = #"FEMALE";
}
}
}
My question is:
a)Why is prepareForSegue not called? Does the Storyboard Embed Segue behave differently to a standard seque?
b)Is there a better way of passing data from the container view to the embedded table?
Also please ignore the messy implementation/various log tests, just my attempts to work out whats going wrong.
My question actually stems from a misunderstanding of how container views load their embedded views. Apparently, it all happens before viewDidLoad. That means my conversion of sGender into containerGender took place too late.
I fixed it by passing sGender to the embedded view directly. I had thought I'd already tried this, but yesterday was obviously a slow day ;).
you can do it..
try
in childViewController
set-
#property(nonatomic,retain)parentViewController *parent;
and
in ParentViewController set-
ChildViewController *child = [[childviewController alloc]init];
child.parent=self;
It will set your parent class in childview and you can get data through parent object in child view controller.

Resources