Passing NSMutableArray with modal view - xcode

I have 2 views, in the second one I initialize a NSMutableArray and I want to pass it back to the first View. In the second view I have a button connected with the following action:
-(IBAction)back:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil]
}
With this action I go back from my second ViewController to the first ViewController, is there a way to pass the NSMutableArray from that action?

If you are not using prepareForSegue then you can user NSUserDefaults:
-(IBAction)back:(id)sender {
NSMutableArray *mutableArray = [[NSMutableArray alloc]init];
[[NSUserDefaults standardUserDefaults]setObject:mutableArray forKey:#"array"];
[self dismissViewControllerAnimated:YES completion:nil];
//I'm guessing you are going to load the viewController that's up next?
}
You can retrieve it in the viewDidLoad like so:
// to retrieve in maybe viewDidLoad?
NSArray * array = [[NSUserDefaults standardUserDefaults]arrayForKey:#"array"];
NSMutableArray *mutableArray = [array mutableCopy];

Related

Why is Switching View Controllers Slow the First Time?

I have a project with two view controllers. When I press a button, the other view is loaded. The first time I do this, the program pauses for a second as the second view controller loads. I have very little in the viewDidLoad method. After I navigate to the second view after the first time, the views are swapped in and out quickly. How can I remedy this/what am I missing?
Also, there is no slow down if I do not create the array in the viewDidLoad method.
Here's my viewDidLoad:
- (void)viewDidLoad
{
NSArray *array = [[NSArray alloc] initWithObjects:#"sound1", #"sound2", nil];
self.listData = array;
[super viewDidLoad];
}
And my button to load the second view:
- (IBAction)soundListButton:(id)sender {
NSLog(#"Pressed!");
BBRViewController * controller = [[BBRViewController alloc]
initWithNibName:#"BBRViewController" bundle:nil];
controller.modalTransitionStyle=UIModalTransitionStyleCoverVertical;
[self presentViewController:controller animated:YES completion:nil];
}

Populating NSOutlineView with bindings - KVO adding of items

I've created a small test project to play with NSOutlineView before using it in one of my projects. I'm successful in displaying a list of items with children using a NSTreeController who's content is bound to an Array.
Now while I created this object it took me ages to realize that my array contents would only show up if i created them in my init method:
- (id)init
{
self = [super init];
if (self) {
results = [NSMutableArray new];
NSMutableArray *collection = [[NSMutableArray alloc] init];
// Insert code here to initialize your application
NSMutableDictionary *aDict = [[NSMutableDictionary alloc] init];
[aDict setValue:#"Activities" forKey:#"name"];
NSMutableArray *anArray = [NSMutableArray new];
for (int i; i<=3 ; i++) {
NSMutableDictionary *dict = [NSMutableDictionary new];
[dict setValue:[NSString stringWithFormat:#"Activity %d", i] forKeyPath:#"name"];
[anArray addObject:dict];
}
results = collection;
}
return self;
}
If I put the same code in applicationDidFinishLaunching it wouldn't show the items.
I'm facing the same issue now when trying to add items to the view. My understanding of using the NSTreeController is that it handles the content similar to what NSArrayController does for a NSTableView (OutlineView being a subclass and all). However, whenever I use a KV compliant method to add items to the array the items do not show up in my view.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSMutableDictionary *cDict = [[NSMutableDictionary alloc] init];
[cDict setValue:#"Calls" forKey:#"name"];
[results addObject:cDict];
[outlineView reloadData];
}
I've also tried calling reloadData on the outlineview after adding an object, but that doesn't seem to be called. What am I missing?
Here's a link to my project: https://dl.dropboxusercontent.com/u/5057512/Outline.zip
After finding this answer:
Correct way to get rearrangeObjects sent to an NSTreeController after changes to nodes in the tree?
It turns out that NSTreeController reacts to performSelector:#selector(rearrangeObjects) withObject:afterDelay:
and calling this after adding the objects lets the new objects appear.

Adding a UIViewController before UIImagePickerController

I have the following code to load a UIImagePickerController which works fine.
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
mediaUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
mediaUI.delegate = self;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
I would like to load a modal view with some help information on how to use the UIImagePickerController:
UIStoryboard *storyboard = self.storyboard;
HelpViewController *svc = [storyboard instantiateViewControllerWithIdentifier:#"HelpViewController"];
[self presentViewController:svc animated:YES completion:nil];
How can I display the UIImagePickerController after the user dismisses the HelpViewController view?
Don't be tempted to move directly from HelpViewController to UIImagePickerController, you need to get there via your mainViewController.
Let's put your code into a method...
- (void) presentImagePicker {
UIImagePickerController *mediaUI = [[UIImagePickerController alloc] init];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
mediaUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie, nil];
mediaUI.delegate = self;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
}
(Note that presentModalViewController:animated is depracated since ~iOS5, and you should really replace it with
[controller presentViewController:mediaUI animated:YES completion:nil];)
Let's call your viewControllers mainVC, helpVC and imageVC. There are two ways you can implement this.
method 1 - performSelector
The quick-and-slightly-dirty solution is to do this in your helpVC's dismiss button method:
- (IBAction)dismissHelpAndPresentImagePicker:(id)sender
{
UIViewController* mainVC = self.presentingViewController;
[mainVC dismissViewControllerAnimated:NO completion:
^{
if ([mainVC respondsToSelector:#selector(presentImagePicker)])
[mainVC performSelector:#selector(presentImagePicker)];
}];
}
It's slightly dirty because you need to ensure that presentImagePicker is implemented in mainVC - the compiler will give you no warnings if it is not. Also you are running a completion block after it's object has been dismissed, so there's no certainty it's going to work (in practice, it does, but still...)
Note that you have to assign the pointer self.presentingViewController's to a local variable (mainVC). That's because when helpVC is dismissed, it's presentingViewController property is reset to nil, so by the time you get to run the completion block you cannot use it. But the local variable mainVC is still valid.
method 2 - protocol/delegate
The clean way to do this is to use a protocol in helpVC to declare a delegate method, and make mainVC the delegate. This way the compiler will keep track of everything and warn you if it is not correctly implemented.
Here are the steps to do that:
In helpVC.h add this protocol above the #interface section:
#protocol helpVCDelegate
- (void) dismissHelpAndPresentImagePicker;
#end
In helpVC.h interface section declare a property for its delegate:
#property (nonatomic, weak) id <helpVCDelegate> delegate;
(the <helpVCDelegate> tells the compiler that the delegate is expected to conform to the protocol, so it will have to implement dismissHelpAndPresentImagePicker)
In helpVC.m your method can now look like this:
- (IBAction)dismissHelpAndPresentImagePicker:(id)sender
{
[self.delegate dismissHelpAndPresentImagePicker];
}
In MainVC, when you create HelpVC (=svc in your code), set MainVC as it's delegate:
HelpViewController *svc = [storyboard instantiateViewControllerWithIdentifier:#"HelpViewController"];
svc.delegate = self;
[self presentViewController:svc animated:YES completion:nil];
And be sure to implement the delegate method dismissHelpAndPresentImagePicker
- (void) dismissHelpAndPresentImagePicker
{
[self dismissViewControllerAnimated:NO completion:^{
[self presentImagePicker];
}];
}
Personally I would always use method 2. But I offered up a that solution earlier today to a similar question, and the questioner seemed to think protocol/delegate was overcomplicated. Maybe my answer just made it seem so, I have tried to simplify it here.

How to pass variable from uitableview to second tableview using didSelectRowAtIndexPath?

i want to pass the variable from a view controller to another one, so that when the user selects a certain row in the first table view, the application will take him to another view controller in which the details of the selected item will appear.
This is my code :
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selectedAuthors = [theauthors objectAtIndex:indexPath.row];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
Details *dvController = [storyboard instantiateViewControllerWithIdentifier:#"Details"]; //Or whatever identifier you have defined in your storyboard
dvController.selectedAuthors = selectedAuthors;
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:authorNAme delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display Alert Message
authorNAme = [[NSString stringWithFormat:[theauthors objectAtIndex:indexPath.row]] intValue];
[messageAlert show];
[self.navigationController pushViewController:dvController animated:YES];
}
selectedAuthors is a string
authorName is a global variable in which i want to store the content of the selected row.
Any help will be highly appreciated.
I see you are using storyboards.
In this case, to send information to the next view controller you have to implement
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
This method gets called every time a segue is about to be performed.
For instance, in didSelectRowAtIndexPath you can save the row's information in a dictionnary and pass it to the next view controller in the prepareForSegue method.
For detailed information you can check out Apple's sample project named SimpleDrillDown. It does the same thing you need to do:
http://developer.apple.com/library/ios/#samplecode/SimpleDrillDown/Introduction/Intro.html
NSString *titleString = [[[NSString alloc] initWithFormat:#"Element number : %d",indexPath.row] autorelease];
This is the simplest function used to send variables and it just came out of nowhere! For anyone lost this is the best function!!

How to update detailViewController.detailItem from multi-level nav in rootViewController

this is my first post so please be gently.
I am using the basic Split View-based application within xcode, but have edited it so that the rootViewController does not simply update the detailViewController, but instead pushes a new UITableViewController (taskViewController) onto the navigation stack.
My problem is, that nothing happens when I now call the following from my taskViewController:
detailViewController.detailItem = [NSString stringWithFormat:#"Row %d", indexPath.row];
If I call this from rootViewController, instead of pushing a new UITableView onto the stack, it works.
Here is my code from rootViewController when a cell is selected:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TaskViewController *taskViewController = [[TaskViewController alloc] init];
taskViewController.title = [NSString stringWithFormat:#"Unit %d",indexPath.row];
[self.navigationController pushViewController:taskViewController animated:YES];
[taskViewController release];
}
Have I done something wrong here? Am I using the navigation controller correctly within the rootViewController of the UISplitViewController?
Your rootViewController can access detailViewController because it has a referance to it. if you push a new controller onto the nav stack, then its not automatically going to know about DetailViewController.
Have you NSLog'd detailViewController in your taskVC to see if it has a pointer?
You would typically set this when you are creating it like this:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TaskViewController *taskViewController = [[TaskViewController alloc] init];
taskViewController.title = [NSString stringWithFormat:#"Unit %d",indexPath.row];
taskViewController.detailViewController = self.detailViewController;
[self.navigationController pushViewController:taskViewController animated:YES];
[taskViewController release];
}

Resources