Using NSNotification to detect UIButton push to change UIWebView - objective-c

I have two buttons in my VC and currently they both are connected to their respective pdf files. There is another button, Push, that goes to the rootviewcontroller. In the RVC I have a UIWebView. How can I make it so that if I push button A, a.pdf is displayed and b.pdf for button B?
I guess, how do I make the rvc listen for this event correctly?
Snippet for UIWebView inside my RVC.m
pdfViewer=[[UIWebView alloc]initWithFrame:CGRectMake(420, 190, 340, 445)];
NSString *path = [[NSBundle mainBundle] pathForResource:#"nameofpdf" ofType:#"pdf"];
NSURL *targetURL = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:targetURL];
[pdfViewer setAlpha: .8];
[pdfViewer loadRequest:request];
[self.view addSubview:pdfViewer];
And button Push in my VC
-(IBAction)pushButtonPressed{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
RootViewController *RVC = [storyboard instantiateViewControllerWithIdentifier:#"Root"];
[UIApplication sharedApplication].delegate.window.RootViewController = RVC;
}
Wrap up:
I first press A or B, then press Push which will bring me to the RVC which will display pdfA or pdfB.

Declare a property for your RVC for the pdf file you want it to open. In your viewController that holds the buttons have the buttonFunction pass the filename to the segue as the sender parameter in prepareForSegue. In prepareForSegue grab the dest view controller and set the property. A short snippet might be more clear
In your viewController with the Buttons:
- (void)buttonA {
[self performSegueWithIdentifier:#"mySegue" sender:#"pdfA.pdf"];
}
- (void)buttonB {
[self performSegueWithIdentifier:#"mySegue" sender:#"pdfB.pdf"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"mySegue"]) {
UIViewController *rvc = segue.destinationViewController;
rvc.pdfToOpen = sender;
}
}
You'll have to adjust your prepareForSegue to use the correct class with the correct property name of course, but this is generally how you should pass information from an action into a view controller via a segue.
Once in your RVC you can access that property, probably inside viewDidLoad, and tell your webView to load the correct pdf.

Related

What's the difference between the back button on UINavigationController and PopTopViewController?

I have a UINavigationController hierarchy, VC1 --> VC2.
VC1 has a table view that I need to reload when VC2 is done with its work, so VC1 has this code:
-(void)viewWillAppear:(BOOL)animated
{
[[self tableView] reloadData];
}
VC2 is essentially working with the server to create a new table row in VC1. When the done button in VC2 is pressed, I call [navController popViewControllerAnimated:YES]. So here's what happens from the user's perspective:
Visit VC2, use it to create a new row for the table in VC1. Press done.
The hierarchy successfully navigates back to VC1, but the tableview does not reload and display the new row.
However, if I then nav forward to VC2, and immediately hit the navController back button, the table does reload and show the new row.
So why does [tableview reload] work on 3 but not 2? Thanks so much.
==
More code in response to answer mentioned below:
In App delegate:
CWLandingVC *lvc = [[CWLandingVC alloc] init];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:lvc];
[[self window] setRootViewController:navController];
In VC0:
-(void)toSessionMgmtViewController
{
TSessionMgmtViewController *tsmvc = [[TSessionMgmtViewController alloc] init];
[[self navigationController] pushViewController:tsmvc animated:YES];
}
In VC1:
- (IBAction)toCreateSessionView:(id)sender
{
TCreateSession *cs = [[TCreateSession alloc] init];
[[self navigationController] pushViewController:cs animated:YES];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[self tableView] reloadData];
}
In VC2:
Finishes working with server...
UINavigationController *navControler = [self navigationController];
[navControler popViewControllerAnimated:YES];
Also, when VC2 is done working with the server, it updates a data store of TSessions called SessionListStore:
- (TSession *)addSession:(NSString *)code withName:(NSString *) name qs:(int)qs
{
TSession *s = [[TSession alloc] initWithName:name code:code numberQuestions:qs];
[_sessions setObject:s forKey:code];
return s;
}
where sessions is a NSNutatbleDictionary in SessionListStore.
Thanks so much in advance.
EDIT: The solution was to trigger the reloadData call from the completion block of Server call.
Please check this answer,
Popping ViewController doesn't call viewWillAppear when going back
Have you added navigation controller to your view controller or view controllers to your navigation controller?
Also, you can set the desired view controller as the delegate of your navigation controller and implement this method.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated

Objective-C: How to switch the NSView by button click

I have different xib files with NSViewController attached to them. (Screenshot below)
One of xib file called StartMenuViewController which has a button. I want to click that button and change the view to DetectingUSBViewController.(Screenshot below)
The IBAction of that button is in StartMenuViewController.m file.
And I use AppController.m to control my main xib view.(NSWindow + NSView) (Screenshot below)
When the application runs, I try to initialize the StartMenuViewController fist by doing the following thing in my AppController.m file.
-(void)awakeFromNib{
[self initialize];
}
-(void) initialize
{
#autoreleasepool {
//mainViewController is a NSViewController and _mainView is a NSView which connect with Custom View in main xib
self.mainViewController = [[[StartMenuViewController alloc]initWithNibName:StartMenuView bundle:nil]autorelease];
[_mainView addSubview:[_mainViewController view]];
}
}
It works fine and it will show the StartMenuViewController.xib on the window at first, but I do not know how to change the view after clicking the button(FIND USB DRIVE). I want the current view changes to DetectingUSBViewController.xib.
Simplest way possible, assuming you have tied your USB button properly in, do the following :
- (IBAction)usbButton:(UIButton *)sender {
DetectingUSBViewController *second = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
load the DetectingUSBViewController in startMenuViewController as DetectingUSBViewController* v1 = [[ViewCont1 alloc] initWithNibName:#"ViewCont1" bundle:nil]; now add or replace the view as [v1 view] in view where you want to add/replace.
You need to hook up your button to send an IBAction
You need a 'View for DetectingUSBViewController.xib'
=> one way (iOS like) is to use a ViewController. Subclass NSViewController and then alloc init a DetectingUSBViewController
Add the view. Don't present the VC (as there is no such thing in OSX)
//button click action
- (IBAction)usbButton:(UIButton *)sender {
//! Retain the VC
Self.detectingUSBViewController = [[DetectingUSBViewController alloc] initWithNibName:#"DetectingUSBView" bundle:nil];
//add the view
[_mainView addSubview:[_detectingUSBViewController view]];
}

QLPreviewController only shows a single file

I am using a QLPreviewController to display a set of files. However, it only shows the first one and I can't seem to swipe or do anything to show the second. What am I doing wrong? Do I have to set it manually? If so - how would I go about doing that?
This is from my AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// normal viewcontroller init here
[self showPreview] ;
return YES;
}
NSArray* documents ;
QLPreviewController* preview ;
- (void) showPreview
{
documents = [[NSArray alloc] initWithObjects: #"photo" , #"photo2" , nil ] ;
preview = [[QLPreviewController alloc] init];
preview.dataSource = self;
preview.delegate = self;
preview.view.frame = [[UIScreen mainScreen] bounds];
//save a reference to the preview controller in an ivar
// self.previewController = preview;
//refresh the preview controller
[preview reloadData];
[[preview view] setNeedsLayout];
[[preview view] setNeedsDisplay];
[preview refreshCurrentPreviewItem];
preview.view.userInteractionEnabled = YES;
//add it
[self.viewController.view addSubview:preview.view];
}
I also declared the two callback functions in the same AppDelegate.m file:
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index
{
NSString* filename = [documents objectAtIndex:index] ; // #"photo" ;
NSURL* returnURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: filename ofType:#"jpg" ]] ;
return returnURL ;
}
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return [documents count];
}
You are displaying it wrong.
QLPreviewController is a UIViewController, which means you basically have 2 ways of displaying it:
Push it into your UINavigationController.
Display it modally (this can be done with or without a UINavigationController - depends if you want a navigation bar).
If you choose option 2 you get "free" navigation arrows to switch between items.
For option 1 you need to create the arrows yourself.
This following is taken from the QLPreviewController documentation:
If there is more than one item in the list, a modally-presented (that
is, full-screen) controller displays navigation arrows to let the user
switch among the items. For a Quick Look preview controller pushed
using a navigation controller, you can provide buttons in the
navigation bar for moving through the navigation list.

Call storyboard scene programmatically (without needing segue)?

I have a modal storyboard scene that I want to be accessible to all my other scenes. Creating a modal segue to it from every scene on my storyboard creates a big mess of strings going everywhere. Is there a way that I leave off the segues and call the scene programmatically instead?
Basically I want to do something like this:
MyNewViewController *myNewVC = [[MyNewViewController alloc] init];
[self presentModalViewController:myNewVC animated:YES];
except instead of creating and pushing a view controller class, I want to do a modal transition to an "isolated" (not connected with a segue) storyboard scene.
Yes you can. Do something like this to get access to the VC, then just Modal Push it:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil];
MyNewViewController *myVC = (MyNewViewController *)[storyboard instantiateViewControllerWithIdentifier:#"myViewCont"];
Note: the method presentModalViewController:animated is deprecated in iOS 6.
The new code should read:
NSString * storyboardName = #"MainStoryboard_iPhone";
NSString * viewControllerID = #"ViewID";
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
MyViewController * controller = (MyViewController *)[storyboard instantiateViewControllerWithIdentifier:viewControllerID];
[self presentViewController:controller animated:YES completion:nil];
In the storyboard give your view controller an identifier (under the Attributes Inspector) then use the following code to bring that view forward.
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"STORYBOARDNAME" bundle:nil];
UIViewController *vc = [mainStoryboard instantiateViewControllerWithIdentifier:#"VIEWCONTROLLERIDENTIFIER"];
[self presentModalViewController:vc animated:YES];
I have a case where I want to present a view controller from the main part of the app, one with settings & help & so on. To do this, I want it to be within a nav controller, sort of a little plug in module we can call from a UIBarButtonItem.
Now, this can be to/in the current storyboard, or to another, it doesn't matter.
I want to do it this way, because I loathe the potential of segue line spaghetti all over my storyboard.
Here's how to do it.
- (IBAction)displaySettings:(id)sender
{
LOG_SELECTOR() // google that for extra goodness
// FYI, this can be done using a different storyboard like so.
/*
NSString * storyboardName = #"MainStoryboard_iPhone"; // possibly use device idiom?
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:nil];
*/
// To push a new set of scenes with a new Navigation Controller, it is done like this:
UINavigationController *settingsNC = [self.storyboard instantiateViewControllerWithIdentifier:#"Settings Nav Controller"];
OBSettingsUIViewController *settingsVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Settings root"];
[settingsNC pushViewController:settingsVC animated:NO];
[settingsNC setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
// Present the view controller;
[self presentViewController:settingsNC animated:YES completion:NULL];
}
In the presented view controllers (or in a subclass of the Navigation Controller), you can have a UIBarButtonItem to then dismiss the whole presented hierarchy of view controllers like so:
- (IBAction)dismissThisVC:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
Hope this helps a bunch of people out. Cheers.
Just call viewcontroller using navigation controller
Write this code in viewcontroller and set viewcontroller in storyboard as set in the image.
ProfileVC *vc = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"ProfileVC"];
[self.navigationController pushViewController:vc animated:YES];
Call to navigate to other class
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UINavigationController *navController = (UINavigationController *)window.rootViewController;
DumpFeed *dump = [storyboard instantiateViewControllerWithIdentifier:#"DumpFeed"];
dump.isPushed=YES;
dump.strUserId = appDelegate.strFriendid;
[navController pushViewController:dump animated:YES];
Heres a Swift version of this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myVC = storyboard.instantiateViewControllerWithIdentifier("myStoryId")
self.presentViewController(myVC, animated: true, completion: nil)
You should also change your storyboard id like this:
I think that with iOS7 it has become very easy implementing via the storyboard
I'm currently learning about the new features in iOS7 and found this simple solution, but it might have been relevant even in prior versions, I'm not sure.
First u need to connect the presenting VC with the target VC (thats the only connection needed), then within the storyboard's attributes inspector choose the style to be modal, in the identity inspector give your VC a storyboardID and make sure you checked the 'use storyboardID' checkbox,
If its not there yet add this method to your presentingVC:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
YourTargetVC * targetVC =
(YourTargetVC *)segue.destinationViewController;
if(nil != targetVC) {
//Do preparations here
}
}
Now, when you wish to show your targetVC from your presentingVC you can use:
[self performSegueWithIdentifier:(NSString *) sender:(id)];
where the identifier is your viewController's storyboardID, and the sender is the view who triggered the action, this method will invoke the storyboards scene, so the [prepareForSegue: sender:] method will be called allowing u making last modifications before the targetViewController will appear.

Animate loaded subview

How would I make this code animate in the SplashView NIB instead of just making it appear (e.g. the UIModalTransitionStyleFlipHorizontal style)? I am using a UITabBarController type project.
- (IBAction)showSplash:(id)sender {
// Hide toolbar
self.tabBarController.tabBar.hidden = YES;
// Splash
[[NSBundle mainBundle] loadNibNamed: #"SplashView" owner: self options: nil];
[self.view addSubview: splashView];
[window makeKeyAndVisible];
}
Bit hard to tell your context with this small bit of code. Basically, if you want to push a viewController modally, in your -(IBAction)showSplash method (you don't need to send the sender if you're not using it, BTW), I would use some code similar to this:
SplashViewController *svc = [[SplashViewController alloc] init]; (assuming nib is same name)
self.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:svc animated:YES];
[svc release];
Then in your SplashViewController you would have an IBAction that calls:
[self dismissModalViewController animated:YES];
You don't actually have to hide the tabBar when you are presenting a modalViewController. It won't be there. The idea of a modalViewController is that it blocks all user interaction with the app except for the modal view, until it is dealt with.
Hope this helps.