I have a simple question in which i've spent a lot of time trying to resolve.
I have a viewcontroller with slider:
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UISlider *slider;
#property (nonatomic) float a;
#end
#implementation ViewController
#synthesize slider,a;
- (IBAction)valueChanged:(id)sender
{
[self setA:self.slider.value];
}
And I have another class where I want to get "A" value, which is value of slider
ViewController *vc = [[ViewController alloc]init];
NSLog(#"%f", [vc a]); //return zero
What im doing wrong?
Thanks
You're instantiating a new view controller which means it's not linking to the current VC you have running with the slider that has a changing value. You have to get a reference to the VC that has the slider and then you can get the "A" property off of it just by using dot syntax NSLog(#"%f", activeVC.a);
Related
I just like to play with coding for a hobby, so probably a noob question;
I have a simple storyboard for MacOS with 2 views. Both have there own classes (main class and subclass). How can I control a outlet in the subclass from the main class?
for example
I have a button (IBAction) in the mainclass and a textfield (IBOutlet) in the subclass. I want to set the stringvalue for the textfield with a click on the button in main.
I have searched a lot last days but just don't get it. (or just need a push in the right direction)
EDIT after JingJingTao's answer:
I used the control-drag function to open the second window.
I tried the code JingJingTao gives, but the textfield doesn't respond to the action.
My classes look like this now:
ViewController.h
#import <Cocoa/Cocoa.h>
#interface ViewController : NSViewController
- (IBAction)newText:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#property (nonatomic) ViewController2 *subclass;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
}
- (void)newText:(id)sender {
self.subclass.textField.stringValue = #"button pressed";
}
#end
ViewController2.h
#import "ViewController.h"
#interface ViewController2 : ViewController
#property (nonatomic) IBOutlet NSTextField *textField;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
}
#end
Update:
I've attached two screenshots of what it looks like in the storyboard for the first suggestion,
1) Add a view to your ViewController, set the class at the top right to 'YourView', 'YourView' is a just an NSView, add a textfield to it and hook it up.
2) Add YourView as a property to your ViewController, i.e. #property (nonatomic) IBOutlet NSView *yourView; and hook it up.
Let me know if there are any issues.
You just need to put the textfield in the public interface of your subclass, so you can access it in your main class, although it does sound like you're using inheritance and I don't think you need to but that's another topic :D.
Example:
In MainClassViewController.m
#interface MainClassViewController ()
#propert (nonatomic) Subclass *subclass;
#end
#implementation MainClassViewController
// I guess you already add your subclass to the main viewcontroller because they display on the same screen.
- (void)yourButtonTapMethod {
self.subclass.textfield.text = #"Your value";
}
In Subclass.h
#interface Subclass : NSObject
#property (nonatomic) IBOutlet UITextfield *textfield;
I use Cocoa Touch instead of Cocoa, so maybe it's NSTextfield for you. Please let me know if this does not answer your question, good luck.
I have an os x app that uses core data.
I have 3 .xib files in my app, those are:
1. MainMenu.xib
2. MasterTableViewController.xib
3. DetailViewController.xib
When started , app displays a view that has NSTableView with couple of records in it.
I name that view MasterTableViewController
I want when user double click on the row, to hide the "master" view and to display my "detail" view. I named that view DetailViewController.
When double clicked on the row in the NSTableView in the "master" view,nothing happen, "master" view remains visible. What I want is "master" view to dissapear, and "detail" view to appear.
Here is the code that I have right now, and more explanations follows:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (nonatomic,strong) NSViewController *mainAppViewController;
#property (weak) IBOutlet NSView *mainAppView;
- (void)changeViewController:(NSInteger)tag;
#property (weak) IBOutlet NSTableView *websitesTableView;
- (void)tableViewDoubleClick:(id)nid;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "MasterTableViewController.h"
#import "DetailViewController.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
- (IBAction)saveAction:(id)sender;
#end
#implementation AppDelegate
NSString *const masterTable = #"MasterTableViewController";
NSString *const detail = #"DetailViewController";
-(void)awakeFromNib {
[_websitesTableView setTarget:self];
[_websitesTableView setDoubleAction:#selector(tableViewDoubleClick:)];
}
- (void)tableViewDoubleClick:(id)nid {
NSInteger rowNumber = [_websitesTableView clickedRow];
NSTableColumn *column = [_websitesTableView tableColumnWithIdentifier:#"websiteUrl"];
NSCell *cell = [column dataCellForRow:rowNumber];
NSInteger tag = 2;
[self changeViewController:tag];
}
- (void)changeViewController:(NSInteger)tag {
[[_mainAppViewController view]removeFromSuperview];
switch (tag) {
case 1:
self.mainAppViewController = [[MasterTableViewController alloc]initWithNibName:masterTable bundle:nil];
break;
case 2:
self.mainAppViewController = [[DetailViewController alloc]initWithNibName:detail bundle:nil];
break;
}
[_mainAppView addSubview:[_mainAppViewController view]];
[[_mainAppViewController view] setFrame:[_mainAppView bounds]];
[[_mainAppViewController view] setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// automatically run the master table view controller
NSInteger tag = 1;
[self changeViewController:tag];
}
Now, some of you may wondering, where is the rest of the code. I have ommited the boiler plate code for the core data below in the AppDelegage.m, since it is unchanged. I used binding to make my NSTableView to work and to display my records, so MasterTableViewController.h and .m files are empty, and same is true for the DetailViewController.h and .m file.
Important note - What i can't understand here: If I change the tag in 2 in the applicationDidFinishLaunching method, detail view is displayed normally, but if i switch it back on 1, and then double click on the row, "master" view (with the NSTableView) remains visible, and nothing happen (views are not swapped)
Anyone can help me to find out what is wrong with my code?
Regards, John
You apparently had a second instance of your AppDelegate class instantiated in the MasterTableViewController.xib file. There should be only one AppDelegate instance and that's the one in MainMenu.xib. So, it shouldn't be in MasterTableViewController.xib.
One of the instances was receiving the double-click action method from the table, but the other one was the one with the outlet to the main window.
You need(ed) to get rid of the second instance and find another way to access the app delegate from the MasterTableViewController.
In my app I'm trying to pass data from the parent view to the child view. However, when I run the app the delegate method isn't being called.
Here is the code on how I implemented the custom delegate:
parent.h
#protocol SLBWallViewControllerDelegate <NSObject>
- (void) pictureToBeUploaded:(id)picture;
#end
#interface SLBWallViewController : UIViewController <UIActionSheetDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate>
- (IBAction)createPotButtonPressed:(id)sender;
#property (weak, nonatomic) id <SLBWallViewControllerDelegate> delegate;
#end
parent.m
[self.delegate pictureToBeUploaded:info[UIImagePickerControllerEditedImage]];//i'm taking the pic from a uiimagepicker
child.h
#interface SLBPostViewController : UIViewController <SLBWallViewControllerDelegate>
#property (weak, nonatomic) IBOutlet UIImageView *picture;
#end
child.m
#pragma mark - Wall View Controller Delegate
- (void)pictureToBeUploaded:(id)picture{
self.picture.image = picture;
}
Is there anything wrong or missing?
Well, the problem probably (edit: confirmed in the comments) is that self.delegate is nil at that point. So you send a message to nil and nothing happens of course. What you have to do is make sure that you assign a Child instance to delegate property before trying to send the message. Something like this for example:
//...
self.delegate = //.. a 'Child' instance
//...
[self.delegate pictureToBeUploaded:info[UIImagePickerControllerEditedImage]];
//(1) In Child in .h file create one property
#property (nonatomic,strong) UIImage * someImage;
//(2) In Child in .m file override the property
-(void)setSomeImage:(UIImage *)someImage{
_someImage=someImage;
self.picture.image = self.someImage;
}
//(3) In Parent in .m file set image to child's 'someImage' property
childsObject.someImage= UIImagePickerControllerEditedImage;
I have a UISlider placed in my main view and I have added a subview UIView (via interface builder) that I have associated with its own class SecondView. I need to pass the value of the slider to my sub view to move a point in the sub view when the slider changes.
I have made changes to the original code and the the below paragraph no longer is accurate. I used used the suggested changes offered by #MatthiasBauch.
I thought it would be simple a matter of sharing an iVar between the two. I created an iVar myPoint using #property (if this is still considered an iVar) in my ViewController interface, set myPoint = sliderValue.value in my ViewController implementation in the IBAction for when the slider value changes. Then in my SecondView implementation I #import "ViewController.h" then call my call my iVar in my SecondView implementation but the way I have done it it only returns nil or 0 instead of the slider value.
I don't want to use global variables.
I have looked at other post that seem to be asking a similar question but I'm still missing the concept, I guess. My code is below.
ViewController.h
#import <UIKit/UIKit.h>
#import "SecondView.h"
#interface ViewController : UIViewController
{
SecondView *secondView; // Do I need this with secondView declared as a #property below?
}
#property (nonatomic, retain) SecondView *secondView;
- (IBAction)sliderChanged:(id)sender;
#property (weak, nonatomic) IBOutlet UISlider *sliderValue;
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#property (weak, nonatomic) IBOutlet UIView *myView;
#end
ViewController.m
#import "ViewController.h"
#import "SecondView.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize sliderValue, myLabel, myView, secondView;
- (void)viewDidLoad
{
[super viewDidLoad];
secondView.thePoint = 50;
NSLog(#"%f", secondView.thePoint); // This is retuning a zero
}
- (IBAction)sliderChanged:(id)sender
{
secondView.thePoint = sliderValue.value;
myLabel.text = [NSString stringWithFormat:#"%.2f", sliderValue.value];
[secondView setNeedsDisplay];
}
#end
SecondView.h
#import <UIKit/UIKit.h>
#interface SecondView : UIView
#property (assign, nonatomic) CGFloat thePoint;
#end
SecondView.m
#import "SecondView.h"
#implementation SecondView
#synthesize thePoint;
- (void)drawRect:(CGRect)rect
{
float aPoint = thePoint;
NSLog(#"%f", aPoint); // this is retuning 0.000000
UIBezierPath *point = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(aPoint, 100, 4, 4)];
[point fill];
}
#end
Tell the view where to draw and don't ask the (newly allocated) viewController where to draw.
You are allocating a new viewController, this viewController of course does not know the value you set in the viewController where you actually changed the slider.
This won't work. Those two viewControllers are not the same instance. They share the same class, but that's it. Values from one viewController instance don't magically appear in a second instance.
Instead you should set a point property of the secondary view in your slider action.
Something like this:
Add a float #property to your view
#interface SecondView : UIView
#property (assign, nonatomic) CGFloat point;
#end
to draw use that point and not the initial value from a new ViewController instance.
- (void)drawRect:(CGRect)rect
{
float aPoint = self.point;
UIBezierPath *point = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(aPoint, 100, 4, 4)];
[point fill];
}
and set the point property of the secondary view in the slider action
- (IBAction)sliderChanged:(id)sender
{
secondView.point = sliderValue.value;
[secondView setNeedsDisplay]; // you might be able to omit that
myLabel.text = [NSString stringWithFormat:#"%.2f", myPoint];
}
Your ViewController has a property called #myView which points to the instance of SecondView created by the runtime.
So, your ViewController's implementation could call the drawRect: method on myView and pass in the relevant coordinates.
Here's some pseudo code for your ViewController.
- (IBAction)sliderChanged:(id)sender
{
myPoint = sliderValue.value;
myLabel.text = [NSString stringWithFormat:#"%.2f", myPoint];
[myView drawRect:CGRectMake(myPoint, 100, 4, 4)];
}
Note however that in your ViewController, myView is just a UIView, not a SecondView. You have a few choices on how to resolve this. The cleanest way is probably to remove the #import ViewController.h from SecondView and instead do the opposite. That is, have ViewController do an #import SecondView.h, then promote myView to a SecondView.
If that doesn't work for some reason (for example, if XCode demands that it remain strictly a UIView), you can still upcast the myView property at runtime like this:
[(*SecondView)myView drawRect:CGRectMake(myPoint, 100, 4, 4)];
Alternatively, you could point your slider's action at myView like the answer to this question does for a button: subclass UIView actions in viewcontroller
As usual in programming, there are several possible solutions. It's up to you to pick the best one for you. Good luck!
I'm trying to have my app take a picture then pass the image onto another view for editing but I can't seem to figure out how to change views, how to add an "ID" to a view in the storyboard or how to pass data between views.
The communication between two UIViewControllers needs to be managed manually, however, if you are using storyboards to create your app, there's some things that you need to take into account.
Let's say you have FirstViewController and SecondViewController(Lets assume you have everything set up in your Storyboard). FirstViewController will pass a UIImage to SecondViewController and they will look something like this.
#interface FirstViewController : UIViewController
- (IBAction)transitionToNextViewController;
#property (retain, nonatomic) UIImage *image;
#end
#implementation FirstViewContoller
- (IBAction)transitionToNextViewController;
{
[self performSegueWithIdentifier:#"SegueIdentifier"];
}
#end
And:
#interface SecondViewController : UIViewController
#property (retain, nonatomic) UIImage *image;
#end
You are probably wondering how are you supposed to pass the image to the SecondViewController. Well, when using storyboards, your UIViewControllers will receive a call to their method prepareForSegue:sender: . All you have to do is set the image property for the second UIViewController there.
#implementation FirstViewController
- (IBAction)transitionToNextViewController;
{
[self performSegueWithIdentifier:#"SegueIdentifier"];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *secondViewController = (SecondViewController *)segue.destinationViewController; // You have to cast it
secondViewController.image = self.image;
}
#end
and that's it. To better understand Storyboards please read the apple docs here.