How to call a UIViewController property in custom uiview? - ios

I have a AVAudioPlayer property in my viewController and I want to draw a circle in my custom uiview if the music is playing.
in my MyViewController.h:
#property (strong, nonatomic) AVAudioPlayer *audio;
in my view.h
- (void) drawCircle
{
//DRAW Circle
}
now i want to check in my View.m if the audio is playing.
i tried to add the following in my View.h
#property (nonatomic, assign) MyViewController *ViewController_audio;
and then do if ([ViewController_audio _audio].playing) { } in
but it didn't work.

Your syntax is wrong. Get rid of the underscore:
if ([ViewController_audio audio].playing)
or
if (ViewController_audio.audio.playing)
Either syntax is valid.
P.S. "...it didn't work" is supremely unhelpful. Always explain what happens. In your case, I'm assuming that you got a compiler error. So copy and paste the full text of the compiler error, and explicitly tell the line on which it occurs.

A view should not have a reference to view controller. This is a bad design.
Instead you should have a flag in view which will be set by your view controller when its playing. The view will read this property & take ui decisions.
From design prospective i would suggest that no decisions should be left to view. It is view controller who has right to think, a view should only display.

Related

Adding tag after switching view controllers

I have a randomly generated int that I assign to a tag for a UIImageView on my storyboard in ViewWillAppear.
When I segue to the main menu and try to enter the view again, however, the app crashes. I know it's because of the tag because when I remove it everything works fine.
Any thoughts on why it works the first time but not on times after that? Code below.
ViewController.h:
#interface ViewController : UIViewController{
int tagnumber;
IBOutlet UIImageView *box;
...
}
ViewController.m:
-(void)viewWillAppear:(BOOL)animated{
tagnumber = arc4random()%1000;
box.tag = tagnumber;
...
}
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
[_animator removeAllBehaviors];
[box removeFromSuperview];
}
MainMenu.m:
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
Basically, when the view disappears and the system is running out of memory, it will call on UIViewController's implementation of didReceiveMemoryWarning. There is a fantastic description of this here: ViewWillDisappear versus dealloc
When you are creating an IBOutput you should really have a weak pointer to it by saying #property (weak, nonatomic) IBOutlet UIImageView *box. Views retain their subviews, and therefore, if a view gets deallocated, its subviews retain count decreases by one. When the view disappears, the system will decide when to deallocate self.view, and when it does, it will automatically release box, and box will get deallocated as well. You don't really need to worry about it.

ios Passing TextView from PushView to PresentingView

I am trying to do the following, and not able to find a straightforward answer.. It is related to this :Passing uitextfield from one view to another. But not exactly.
I have a Firstview.m, from which I push to a Secondview.m. The Secondview.m has a UITextView. I allow the user to edit the UITextView on Secondview.m. Now I want to store this text value in a variable in Firstview.m. One way to to do this is as follows
in Firstview.h
#property (nonatomic) Secondview *secondView;
That is keep a secondView variable in Firstview itself. But this doesn't seem efficient. Ideally I should only have 1 NSString text field in FirstView. What is the right way to do this ? Thanks
You can achieve this by using Delegation in Objective-C.
In your SecondView.h add following right after Header Inclusion
#protocol YourDelegateName <NSObject>
-(void)setText:(NSString *)strData;
#end
Also add delegate property to your header for accessing them in calling class, like below (This goes with other properties declaration in SecondView.h file):
#property (nonatomic, weak) id<YourDelegateName> delegate;
Now, Comes the calling the delegate part. Say, you want to save the text value of UITextView of SeconView in strTextViewData of FirstView class, when the following event occurs:
- (IBAction)save:(id)sender
{
[self.delegate setText:self.txtView.text]; // Assuming txtView is name for UITextView object
}
Now, In FirstView.h add YourDelegateName in delegate list like below:
#interface FisrtView : ViewController <YourDelegateName>
#property (nonatomic, reatin) NSString *strTextViewData;
#end
And then in FisrtView.m file when you create instance of SecondView class, set delegate to self like below:
SecondView *obj = [[SecondView alloc] initWithNibName:#"SeconView" bundle:nil];
obj.delegate = self; // THIS IS THE IMPORTANT PART. DON'T MISS THIS.
Now, Implement the delegate method:
-(void)setText:(NSString *)strData
{
self.strTextViewData = strData;
}
Applying this to your code will do what you want. Also, Delegation is one of the most important feature of Objective-C language, which - by doing this - you will get to learn.
Let me know, if you face any issue with this implementation.

Xcode - Update label text when button is pressed in other view

Newbie question for Xcode gurus...
I have two views. They both use the same custom class. In view_1 I have a button and when this is pressed view_2 will show. In view_2 I have a label which will have it´s text changed when I press the button in view_1. As of now the Label_1 is nil when I set a breakpoint at it and therefor useless. How can I get to update this label when I press the button? Her are some snippets from my code...
This is my .h file:
#interface ViewController : UIViewController
{
IBOutlet UIButton *buttonSelectTimeInterval;
IBOutlet UILabel *labelTimer;
}
#end
This is the button action in my .m file:
- (IBAction)startPouring_ButtonClick:(id)sender
{
labelTimer.text = #"foo";
}
…but my .m file doesn't seem to know the labelTimer since it is a ´nil´. Why is this so? It is instantiated in the .h file.
Anyone?
You can use NSNotificationCenter. Put this in you IBAction.
[[NSNotificationCenter defaultCenter] postNotificationName:#"buttonPressed" object:nil];
And this to your viewDidLoad.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(selectorhere) name:#"buttonPressed" object:nil];
somewhere in your .m
(void)selectorhere {
labelTimer.text = #"foo";
}
You can use NSNotificationCenter for this.
Here are the apple documentation link.
First, nothing is "instantiated" in the .h file - that's just the public listing of what properties and methods are available to other classes. Think of the header file as a table of contents, but only for the things the class wants others to see.
Those properties don't exist in memory until the instance of the class itself is created, and then only if you set them to some initial value once they're needed.
How & where are you creating the 2nd view? Is it a storyboard segue or something? The 1st view doesn't seem to have any way of knowing the 2nd one exists, so it won't be able to see or access the label.
View1Class.m
#import View2Class.h
#implementation View1Class
- (IBAction)startPouring_ButtonClick:(id)sender {
//Instantiate the 2ndView when you need it.
// This gives View1 a reference to View2 and its public UILabel.
View2Class * my2ndView = [[View2Class alloc] init];
my2ndView.labelTimer.text = #"foo";
}
#end
As I said, it's still not clear how/where you're actually displaying the 2nd view though, so the snippet above is incomplete. You could use a modal w/a delegate, or this is where NSNotificationCenter is a helpful option - the 2nd view can sign up to get notifications & change accordingly. There are numerous tutorials about creating a 2nd/modal view and displaying it on a button click - you should probably look at those to clarify how the structure of such an app ought to work.
This answer should get you on the right track.
Other specific issues:
Why is the label nil? Because there isn't one...
In this IBAction, which seems to be in View 1:
- (IBAction)startPouring_ButtonClick:(id)sender
{
labelTimer.text = #"foo"; //this is looking for labelTimer in the clicked view.
}
... it is looking for its own labelTimer IBOutlet (in which case it should probably be self.labelTimer.text), and not that of the 2nd view. If the 1st view doesn't even have a UILabel IBOutlet, this is another problem.
If the views have different functions & different properties, they probably shouldn't be instances of the same custom class. If the 1st view doesn't have or need a UILabel, it shouldn't have one in its .h. If the 2nd view doesn't have or need a button it shouldn't have one in its .h. If the views serve different purposes, then make them different classes.
BTW,
Since you're using instance variables for your IBOutlets, you'd need to write your own getter & setter methods if you want to change their values. Did you? To make those values accessible to other classes, you'd need to make those methods public & put them in the .h. It's not good practice for an instance to set its instance variables directly w/o a getter/setter, and other objects definitely should not.
The preferred method is to use #properties for your IBOutlets instead of declaring them as instance variables. This will automatically create the getter & setter methods, backing store in memory, and as of XCode 4.4 it automatically adds #synthesize so you no longer need to do so. Declaring your IBOutlets as "weak" references prevents retain cycles & memory leak, where the view holds on to the outlets & the outlets hold on to the view & nothing ever goes away...
View1Class.h
#interface ViewController : UIViewController
#property (nonatomic, weak) IBOutlet UIButton *buttonSelectTimeInterval;
#end
View2Class.h
#interface ViewController : UIViewController
#property (nonatomic, weak) IBOutlet UILabel *labelTimer;
#end

How to set label text to a variable as the view loads?

So I have this little project in which the user goes from one view to another as they click buttons, and the text on the last button they've clicked should show up in a label in the top of the screen. I figured out how to have the variables accessible from anywhere in the app, and also how to change it as the user presses the buttons. Yet, I can only make the label's text change once a button is hit, and I wanted it to happen automatically (the view to appear with the label already containing the correct text).
For that I set the label in two different ways (which I found online):
#interface ViewMateria : UIViewController
{
IBOutlet UILabel *materiaLabel;
}
#end
and
#interface ViewMateria : UIViewController
#property (weak, nonatomic) IBOutput UILabel *materiaLabel;
#end
Still, for both of this I can not access the label by a simple materiaLabel.text or anything like that, and can't find a way to do it without the need for the press of a button.
I've been looking for an answer for this for a while now, and nothing that I found seemed to be of use for me (since most of the links I found taught how to change a label text with the press of a button).
This is my first project with Objective-C and Xcode, and I don't really know the answer, so maybe I am missing something quite obvious, but still, if anyone could point me in the right direction, that would be of much help.
Put this in your .h file for the view controller:
#property (weak, nonatomic) IBOutput UILabel *materiaLabel;
When you are about to present the view controller, access it like this:
your_ViewMateria_object.materiaLabel.text = #"";
Then present it..
Are you using segues?
If yes, its another story..
UPDATE:
For segues use this, with the .h property value I just mentioned:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ViewMateria *vm = [segue destinationViewController];
vm.materiaLabel.text = #"Whatever";
}
You should be good to go now ;D
Did it work?
UPDATE
In second view controller .h file
#property (strong, nonatomic) NSString *buttonName;
.m file
self.materiaLabel.text = self.buttonName;
In first view controller .m file
inside IBAction
secondviewcontrollerObject.buttonName = [(UIButton *)sender currentTitle];

Drawing with Drawrect

dear objectiveC masters,
I'm a newbie apple programmer and since I'm currently taking a master degree in math education, I want the make a thesis on making apps that based on math education..
Right now, I'm trying to make an iPad app that draws a sine function and then transforms the sine function. I draw the sine graph by overriding the drawrect function in a custom uiview class and load it to a uiview object. The sine function is drawn nicely on a context, along with grids and axes that are drawn on different contexts.
I put several sliders and then plan to use the sliders to change the variables in the uiview class that i use for drawing. Now here's the problem, I realize that I can't access the variables in the viewcontroller from the custom uiview class, and I suspect that I may have mistakenly used the wrong paradigm in writing the whole program.
Can someone help me to clear the confusion here? It doesn't have to be in the exact codes but more to the big pictures of how I should draw and redraw the sine function on a view object whilst changing the variables of the sine function through sliders.
Thank you for your kind help :)
Chandra from Indonesia.
There are two ways to solve this:
Instead of letting the UIView ask the values from the UIViewController, you can also push the values to the UIVIew the moment one of the sliders changes. This way the UIView does what it should do: draw what the ViewController asks him to.
Think of a function like redrawUsingNewValues: that you implement in the UIView and you call from the UIViewController.
Use delegation. If you really want the UIView to be in control, you can give it a pointer to the UIViewController using delegation. That way the UIView doesn't own the UIViewController, but you can get the values you want.
An introduction on delegation can be found here: Delegation and the Cocoa Frameworks
Good luck on your program!
A method in the UIViewController should recognize when the slider values changes
the same method should trigger another methode within the UIViewController to update/recalculate the sine function values (e.g. creating an value array)
at the end of the update-methode the necessary values are transferred to the UIView via an outlet from UIViewController to the UIView (the UIView is an property of the UIViewController)
the UIView is drawing the new sine-function in draw rect
Edit 1:
your ViewController.h:
#import <UIKit/UIKit.h>
#class YourGraphUIView; // that's you view where you draw
#interface ResultViewController: UIViewController
#property (weak, nonatomic) IBOutlet UISlider *valueFromSlider; //bound to your UISlider
#property (weak) IBOutlet YourGraphUIView *yourGraphUIView; //bound to your costumUIView
#property (nonatomic, retain) NSNumber *graphValue;
- (IBAction)takeSliderValue:(id)sender; //bound to your UISlider
#end
your ViewController.m:
#import "ResultViewController.h"
#import "YourGraphUIView.h"
#interface ResultViewController ()
#end
#implementation ResultViewController
#synthesize yourGraphUIView, valueFromSlider, graphValue;
- (IBAction)takeSliderValue:(UISlider *)sender{
graphValue = [NSNumber numberWithDouble:[(double)sender.value]]; //takes value from UISlider
yourGraphUIView.graphValue = graphValue; //gives the value to the yourGraphUIView
[self.yourGraphUIView setNeedsDisplay] //<--- important to redraw UIView after changes
}
end
your YourGraphUIView.h:
#import <UIKit/UIKit.h>
#interface YourGraphUIView : UIView
#property(nonatomic, retain)NSNumber *graphValue;
- (void)drawRect:(CGRect)dirtyRect;
#end
your YourGraphUIView.m:
#import "YourGraphUIView.h"
#implementation YoutGraphUIView
#synthesize graphValue;
//... init, draw rect with using the graphValue for calculating and updating the graph
end;
I hope this helped. You should have a look how to build the GUI and how to connect the UIViews. You need to set the custom classes for the ViewController and the YourGraphUIView as well. Good luck!

Resources