I have a UITabBarController based app. I've made a masterVC Class, all ViewControllers that make up the tabBarController are subclasses of the masterVC. I want to set an UIImageView (which is a property of masterVC) that once set shows that image on each view within the tabBarController.
If I was instantiating each VC I could pass the image as a property (this would be simple). However, there's no method to do this between tabBarController ViewControllers.
The easiest conceptual example of what I'm trying to do is by this example in each view Controller within the tabBarController. There has to be a better way:
-(void)viewDidAppear:(BOOL)animated
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:kMainImageData];
if (data) {
self.mainImageView.image = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
}
-(void)viewWillDisappear:(BOOL)animated
{
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.mainImageView.image];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:kMainImageData];
}
Well there is, create a proper data source, where each UIViewController can request data. There are some ways:
Save the image to disk, use a helper class to retrieve it.
Save the image as property of a Singleton and retrieve it.
You could overload the method
-(id) initWithCoder:(NSCoder*)aDecoder
With something like this:
self = [super initWithCoder:aDecoder];
if ( self )
{
static UIImage *reuseImage = nil;
if ( reuseImage == nil )
{
//Init reuseImage with your image
}
myImageViewProperty.image = reuseImage;
...
return self;
If I'm understanding you correctly, I think you can do this all in your superclass with key-value observing.
In your masterVC header, declare:
#property (strong) UIImage *sharedImage;
And in the implementation:
#synthesize sharedImage;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[self addObserver:self forKeyPath:#"sharedImage" options:NSKeyValueObservingOptionNew context:NULL];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"sharedImage"]) {
self.mainImageView.image = self.sharedImage;
}
}
- (void)dealloc {
[self removeObserver:self forKeyPath:#"sharedImage"];
}
Then, whenever the sharedImage property is set on any of the subclasses, your image view will update its contents accordingly.
I think the easiest thing would be to move the viewDidAppear method you posted into your masterVC class. Then in your ViewControllers that subclass masterVC you can:
Remove the viewDidAppear method if you have no other setup to do, it will then call the viewDidAppear that is in your masterVC.
OR
Change viewDidAppear to the following so that it will call viewDidAppear in masterVC then do all your other setup.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// your other code...
}
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Passing Data between View Controllers
I have 2 modal views. The first modal view is used to edit quantity and price; the second modal view is used when we click the price textfield of first modal view in order to give give reason why we change the price and we can put new price in price textfield of modal view. I want the price in first modal view change when I set the price in second modal view. How to catch the value of second modal view to put in first modal view ?
Use NSNotification center
You have to addobserver event in First Modalview
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reload:) name:#"refresh" object:nil];
}
- (void)reload:(NSNotification *)notification {
textfield.text= [[notification userInfo] valueForKey:#"price"] ;
}
In second modalview you have to post notification after you complete edit
(pass your textfield value)
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:#"333" forKey:#"price"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:nil userInfo:userInfo]
;
Finally remove observer
-
(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"refresh" object:nil];
}
You can used Singleton just to save some data on that class
The following simple steps will make you able to do this.
In the first Modal ViewController, you can declare a function like
- (void) setUpdatedValueWithValue: (NSString *) newValue
{
self.objTextField.text = newValue;
}
Declare this function on the header file too, so that we can access it from the other class.
In the second Modal ViewController
SecondViewController.h
#interface SecondViewController : UIViewController
{
id objFirstViewController;
}
#property (nonatomic, retain) id objFirstViewController;
#end
SecondViewController.m
#implementation SecondViewController
#synthesize objFirstViewController;
#end
Before you present the SecondViewController pass the object of FirstViewController to SecondViewController like,
- (void) presentSecondViewController
{
SecondViewController *objSecondViewController = [[SecondViewController alloc] init];
objSecondViewController.objFirstViewController = self;
[self presentModalViewController: objSecondViewController animated: YES];
[objSecondViewController release];
objSecondViewController = nil;
}
Then, in the function you are calling to dismiss the SecondViewController after the value edit you can do like,
- (void) finishEdit
{
if([objFirstViewController respondsToSelector: #selector(setUpdatedValueWithValue:)])
{
[objFirstViewController performSelector: #selector(setUpdatedValueWithValue:) withObject: editedTextView.text];
}
[self dismissModalViewControllerAnimated: YES];
}
Hope this helps.
set you object with your keyword
[[NSUserDefaults standardUserDefaults]setObject:#"value of second modal view" forKey:#"keyName"];
than get that object in first modal view
NSString *name = [[NSUserDefaults standardUserDefaults]objectForKey:#"keyName"];
I am trying to set up something where the IBAction from view controller 1 would set the ImageView image in View Controller 2's viewDidLoad using tags to differentiate between the buttons pressed.... Something like (not exact code...just hashing it out in my head):
In View Controller 1:
-(IBAction)buttonpressed:(id)sender {
if (button.tag == 1) {
ViewController2ImageView.image = [UIImage imageNamed:#"image1.png"];
}else if (button.tag == 2) {
ViewController2ImageView.image = [UIImage imageNamed:#"image2.png"];
}
In View Controller 2:
-(void)viewDidLoad {
ViewController2ImageView.image = [UIImage imageNamed:#"?.png"];
}
The issue would be how to get the info from the IBAction to pass to the second view controller and having the viewDidLoad method load the correct image.
Ive seen examples converting data to NSString and passing it that way however I was really wondering if there was a better way to go about this.
Ive been able to Google my way through putting a few apps together so far however this has had me scratching my head for a few days now.
Any help or suggested code would be helpful! Even if its just a push in the right direction.
Thanks!
When the button is pressed in viewController1, do something like this:
-(IBAction)buttonpressed:(id)sender {
if (button.tag == 1) {
[[NSUserDefaults standardUserDefaults] setObject:#"image1.png"
forKey:#"viewController2SelectedImageKey"];
} else if (button.tag == 2) {
[[NSUserDefaults standardUserDefaults] setObject:#"image2.png"
forKey:#"viewController2SelectedImageKey"];
} else {
//set some default string for the image
[[NSUserDefaults standardUserDefaults] setObject:#"yourDefaultImage.png"
forKey:#"viewController2SelectedImageKey"];
}
}
Then in your viewDidLoad method in viewController2 do something like this:
- (void)viewDidLoad {
ViewController2ImageView.image = [UIImage imageNamed:[[NSUserDefaults
standardUserDefaults] objectForKey:#"viewController2SelectedImageKey"]];
//other setup
}
This code sets a string to a key in the NSUserDefaults plist (the key I used is #"viewController2SelectedImageKey" but you can use any string you like), which is referenced by viewController2 upon its viewDidLoad method and uses the string as the name of the image file.
Why not use a NSString *imageName property to pass the filename to View Controller 2?
Hi You can do simply with many type as below
1)you can write the method
(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle )nibBundleOrNil andImageName:(NSString)ImageName;
write this mehod in the second view & call from the first view and when this method call at that time store this image name in the second local variable like below
(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle )nibBundleOrNil andImageName:(NSString)ImageName
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
//Local Variable Assignment
imageName=ImageName;
}
return self;
}
and then pass it in ur code means in ur
(void)viewDidLoad {
ViewController2ImageView.image = [UIImage imageNamed:imageName];
}
2)Second type is create imageName Varibale in the secound view and give #property and #synthesize it and than use it at below
SecoundView *ObjSecoundView=[[ObjSecoundView alloc] initWithNibName:#"SecoundView" bundle:nil];
ObjSecoundView.imageName=#"Image1.png";//put ur dynamic image name
[self.navigationController pushViewController:ObjSecoundView animated:YES];
pass this and use in the viewdid load method as below
(void)viewDidLoad {
ViewController2ImageView.image = [UIImage imageNamed:imageName];
}
I have a view controlled app. On my xib I have no webviews but I do have buttons that bring up classes that have webviews. So hit button one and a uiwebview pops up so on and so forth.
Now in one of my classes I pull up a remote webpage that has a link on it. I want to over-ride that button link with shouldStartLoadwithrequest. How ever this never seems to get called.
Right now my class is called Tenth.m and I have this code in my view controller
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#" Test spot 1");
NSString* scheme = [[request URL] scheme];
if ([#"didTap" isEqual:scheme]) {
// Call your method
NSLog(#" Test spot 2");
[self didTapButton1];
return NO;
} else {
NSLog(#" Test spot 3");
return YES;
}}
But I get nothing (none of my NSLogs). I have tried putting this into my Tenth.m class and still nothing. I have looked at other examples and even downloaded one but it only uses the viewcontroller and delegates classes. No third class.
I'm lost as to why its not getting called.
Here is my third class
#import "Tenth.h"
#implementation Tenth
- (void)awakeFromNib
{
[category10 loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.mywebsite.com/api/didtap.php"]]];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#end
remote page code
hello
Tenth.h file
#import <UIKit/UIKit.h>
#interface Tenth : UIViewController <UIWebViewDelegate> {
IBOutlet UIWebView *category10;
}
-(IBAction)back;
#end
My first guess is that the Web view does not have its delegate set. In order for it to call
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
The class containing this method needs to be set as the webview's delegate. So somewhere in the code there should be a line similar to webView.delegate = <variable>, where the variable is the instance of the class which has implemented the shouldStartLoadWithRequest: method.
This is often "self" when the webView is a subview of a viewController's view. But the way you have described your application, I am not sure if it will be self or not, but it sounds like it will not be self, but the name of the instance of a different class.
Maybe try this:
- (void)viewDidLoad
{
[super viewDidLoad];
// Remember to set web view delegate to self.
category10.delegate = self;
}
I am building an application which should allow the user to scroll through the images. Since I have many images (downloaded from the web), what i doing is I have UP and down button on the parent view, in addition i have the scroll view. Based on the selected option (up or down), I add the ImageClass ( created a class which extends UIViewController) view to the scroll view.
Now, on the selected view the user can mark a point or do any stuff.
The question is how from the parent view I can call methods of the Uiviewcontroller. I know how I can set the delegate methods but what I want is that parent controller can call any a method say redraw method which would redraw the entire view.
Code:
-(IBAction) down:(id) sender{
[scrollView2 removeFromSuperview];
}
-(IBAction) down :(id) sender {
[scrollView2 removeFromSuperview];
if(scrollView2 == nil)
scrollView2 = [[UIScrollView alloc] init];
[self.view addSubview:scrollView2];
[self.view sendSubviewToBack:scrollView2];
[scrollView2 setBackgroundColor:[UIColor blackColor]];
[scrollView2 setCanCancelContentTouches:NO];
scrollView2.clipsToBounds = YES;
// default is NO, we want to restrict drawing within our scrollview
scrollView2.indicatorStyle = UIScrollViewIndicatorStyleWhite;
// CSImageView is a class which of the type UIViewController
imageVie = [[CSImageView alloc] init];
[scrollView2 addSubview:imageVie.view];
[scrollView2 setContentSize:CGSizeMake(1500,1500)];
[scrollView2 setScrollEnabled:YES];
[imageView release];
}
Now, from the parent view controller I want to call say:
imageVie.redraw(); method
Code for CSImageView
#interface CSImageView : UIViewController {
NSNumber *imageId ;
}
#property (nonatomic, retain) NSNumber *venueId;
-(void) redraw;
#end
#implementation CSImageView
#synthesize imageId;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void) redraw {
NSLog(#"I am ehre in the test function");
}
#end
Can you please help me on the same. I am not able to call the redraw method. Any input would be appreciated.
First, CSImageView should probably be a subclass of UIView, not UIViewController. You should keep a reference to your instance (i.e. as an instance variable or synthesized property) so you can access it from methods other than - down:.
Wow.
I can't say I follow what you've coded, but here's how you do it.
During this part...add a tag to the view
// CSImageView is a class type UIViewController
imageVie = [[CSImageView alloc] init];
imageVie.tag = 99 // Any number. Preferably a constant
[scrollView2 addSubview:imageVie.view];
...
Then on the parent
view controller. You can ...
-(IBAction) down:(id) sender {
CSImageView *view = [scrollView2 viewWithTag:99];
[view redraw];
... }
Something like that.
My main class MMAppViewController has an "IBOutlet UIImageView *padlock". This controller pushes a Level1View view which is my quiz game. The MMAppViewContoller has 2 buttons level 1 and level 2. Level 2 has the padlock on it and will unlock when a certain score is reached. When the MMAppViewController is pushed back, is there a way to hide the padlock. I know the following code will do this but my problem lies in where to put the code:
if(theScore>4){
[padlock setHidden:TRUE];
}
With my Level1View i can put code in the "viewdidload()" section, but it does not work with my main view because it only seems to load once! I tried puting the code in my Level1View class but keep getting errors about tokens or it being undeclared:
[MMAppViewController padlock setHidden:TRUE];
or
[padlock setHidden:TRUE];
Is there a way of either putting this code in my Level1View class, or is there a way of having the code in my MMAppViewContoller class that will work when Level1View is "unpushed"?? (not sure of terminology)
Not knowing more about the structure of your program it's hard to know the right way to achieve this.
There are several possible approaches, but viewDidLoad is only going to be called once and should be used for setting up the view initially, and not for this sort of repeated logic. You probably have a model object somewhere that holds the score. (If you don't, i.e. if theScore is an instance variable on your ViewController, as your snippets might imply, you should move it to it's own model object.) The best way to go about this would be for your ViewController to "observe" the model object that holds the score using Key-Value Observing. Here's how you might achieve that:
Let's say you have the following model object to hold your game session data (here, only the current score):
#interface GameSession : NSObject
#property (readwrite) double score;
#end
... and its corresponding implementation ...
#implementation GameSession
#synthesize score;
#end
And then assuming you have a ViewController declaration that looks something like this:
#class GameSession;
#interface MyViewController : UIViewController
{
GameSession *game;
IBOutlet UIImageView *padlock;
}
#end
You could set up the following methods on the ViewController, such that every time the score value of the model object is modified, the ViewController will automatically update the hidden state of the padlock image view:
- (void)viewDidLoad
{
[super viewDidLoad];
game = [[GameSession alloc] init];
[game addObserver:self forKeyPath:#"score" options:NSKeyValueObservingOptionInitial context: [RootViewController class]];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == [RootViewController class])
{
if ([keyPath isEqualToString: #"score"])
{
NSNumber* newValue = [change objectForKey: NSKeyValueChangeNewKey];
double currentScore = [newValue doubleValue];
[padlock setHidden: (currentScore < 4.)];
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
[game removeObserver:self forKeyPath:#"score"];
[game release];
game = nil;
[super dealloc];
}
For a full explanation of Key-Value Observing, see this web page: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/
Let me know if this isn't clear.
The simple option is to put the code in viewWillAppear:.