I'm creating a NSTextView in my AppController.h:
#interface AppController : NSObject {
IBOutlet NSTextView *texto;
}
#property (assign) IBOutlet NSTextView *texto;
#end
After connected and properly checked, I'm trying to set a texto for this TextView from another class (AppMenu.m), but with no luck:
#import "AppController.h"
- (IBAction)setText:(id)sender {
AppController *appControl = [[AppController alloc] init];
[[appControl texto] setString:#"Hello"];
}
What should I do?
The problem is that Appmenu creates a new instance of texto, a local one just for appmenu (with the same properties), and not setting properties on the one actually in appcontroller. If you try debugging, you'll see that the two texto objects have different memory pointers.
You could make appcontroller the delegate for appmenu and create a 'setTextoProps' method which can pass data from appmenu over to appcontroller.
You could also make an instance of storyboard.appcontroller and set data directly with something like
Appcontroller *controller = [self.storyboard instantiateViewControllerWithIdentifi er:#"appcontroller"];
[self.controller.texto setText...];
When you call alloc you create a new object. What you need is a reference to the AppController that already exists.
(I'm assuming the text view is already displayed by an AppController object before you execute the code that tries to change its field.)
Related
I have two questions :
When I try to call a method from different class (this method modify a textfield after having checked a condition) the method is well called (the NSLog in statutInternet works) but the TextField isn't modified..
When I do it from the (IBAction)internet method it works .. Any solution ?
Why Xcode want me to called my variables (like internetTextfield) with a _ before it ?
WindowsController.h
#import <Cocoa/Cocoa.h>
#interface WindowController : NSWindowController
#property (assign) IBOutlet NSTextField *internetLabel;
- (void)statutInternet;
- (IBAction)internet:(id)sender;
#end
WindowsController.m :
#import "WindowController.h"
#implementation WindowController
- (IBAction)internet:(id)sender;
{
[self statutInternet];
}
- (void)statutInternet;
{
NSLog(#"Callfunctionworks");
if (condition) {
[_internetLabel setStringValue:#"TxtFieldWorks!"];
}
}
I try to call the method statutInternet with this from another class :
WindowController *fenetre = [[WindowController alloc] init];
[fenetre statutInternet];
When I try to call a method from different class it doesn't work:
That's because, You're making another WindowController instance using this code:
WindowController *fenetre = [[WindowController alloc] init];
This is another new separate instance of same class, which I guess you're not showing. So you want to take reference to the window that's already showing rather than making a new instance.
Why Xcode want me to called my variables (like internetTextfield) with a _ before it ?
That's because when you declare variable using #property it does three things:
Makes an internal variable by adding the conventional underscore (_) to the start of the variable name. That's why you've _ as prefix of your variable.
Makes a setter-getter methods.
Takes the keywords you used (ie. assign, strong, weak) in account while implementing the setter-getters.
You can read a good discussion here: #property and retain, assign, copy, nonatomic in Objective-C
The NSTextField (and all of the other UI items) is not created yet when you call statutInternet method.
When your window loaded, your views will be ready :
_fenetre = [[WindowController alloc] initWithWindowNibName:#"WindowController"];
[_fenetre showWindow:_fenetre.window];
[_fenetre statutInternet];
I have a main window with a couple of popupbuttons. I want to clear them, then load the lists from a method in a custom class. I've got my view controller working and I know the method in the custom class (newRequest) is working because I added a NSLog command to print "Test" when the method executes. In AppDelegate I'm calling the method via:
[polyAppRequest newRequest];.
As I said, I know the method is executing. Why can't I removeallitems from the popupbutton from this custom class method?
Thanks
Keith
I read that you should use an NSWindowController to manage a window. See here:
Windows and window controllers
Adding views or windows to MainWindow
Then if your window gets complicated enough, the NSWindowController can employ various NSViewControllers to manage parts of the window.
In any case, I used an NSWindowController in my answer.
The image below shows the outlet's for File's Owner, which is my MainWindowController:
I created MainWindowController .h/.m in Xcode6.2 by:
Selecting File>New>File>OS X - Source - Cocoa Class
Selecting NSWindowController for Subclass of:
Checking also create .xib file for user interface
Then I deleted the window--not the menu--in the default MainMenu.xib, and I changed the name of MainWindowController.xib, created by the steps above, to MainWindow.xib.
The following code works for me (but I'm a Cocoa beginner!):
//
// AppDelegate.m
// PopUpButtons
#import "AppDelegate.h"
#import "MainWindowController.h"
#interface AppDelegate ()
#property(strong) MainWindowController* mainWindowCtrl;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[self setMainWindowCtrl:[[MainWindowController alloc] init]];
[[self mainWindowCtrl] showWindow:nil];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end
...
//
// MainWindowController.m
// PopUpButtons
//
#import "MainWindowController.h"
#import "MyData.h"
#interface MainWindowController ()
#property(strong) MyData* data;
#property(weak) IBOutlet NSPopUpButton* namePopUp;
#property(weak) IBOutlet NSPopUpButton* agePopUp;
#end
#implementation MainWindowController
-(id)init {
if (self = [super initWithWindowNibName:#"MainWindow"]) {
_data = [[MyData alloc] init]; //Get data for popups
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
[[self namePopUp] removeAllItems];
[[self namePopUp] addItemsWithTitles:[[self data] drinks]];
[[self agePopUp] removeAllItems];
[[self agePopUp] addItemsWithTitles:[[self data] extras]];
}
#end
...
//
// MyData.h
// PopUpButtons
//
#import <Foundation/Foundation.h>
#interface MyData : NSObject
#property NSArray* drinks;
#property NSArray* extras;
#end
...
//
// MyData.m
// PopUpButtons
//
#import "MyData.h"
#implementation MyData
- (id)init {
if (self = [super init]) {
_drinks = #[#"coffee", #"tea"];
_extras = #[#"milk", #"sugar", #"honey"];
}
return self;
}
#end
I hope that helps. If you need any more screenshots, let me know.
Edit1:
I think I see what you are asking about. Although I don't think it is a very good approach, if I change my code to this:
//
// MyData.h
// PopUpButtons
//
#import <Cocoa/Cocoa.h>
#interface MyData : NSObject
#property (copy) NSArray* drinks;
#property (copy) NSArray* extras;
-(void)newRequest;
#end
...
//
// MyData.m
// PopUpButtons
//
#import "MyData.h"
#interface MyData()
#property (weak) IBOutlet NSPopUpButton* drinksPopUp;
#property (weak) IBOutlet NSPopUpButton* extrasPopUp;
#end
#implementation MyData
- (id)init {
if (self = [super init]) {
_drinks = #[#"coffee", #"tea"];
_extras = #[#"milk", #"sugar", #"honey"];
}
return self;
}
-(void)newRequest {
[[self drinksPopUp] removeAllItems];
[[self drinksPopUp] addItemsWithTitles:[self drinks]];
[[self extrasPopUp] removeAllItems];
[[self extrasPopUp] addItemsWithTitles:[self extras]];
}
#end
I am unable to populate the NSPopUpButtons. This is what I did:
I dragged an Object from the Object Library to the dock in IB, and in the Identity Inspector, I changed the Object's class to MyData.
Then I clicked on the Connections Inspector, and the two instance variables in MyData, drinksPopUp and extrasPopUp, were listed in the Outlets.
I dragged from the outlets to the respective NSPopUpButtons.
I guess I assumed, like you, that when my program ran, the NSPopUpButtons would be assigned to the instance variables drinksPopUp and extrasPopUp--but that doesn't seem to be the case. According to the Apple docs, you should be able to do that:
An application typically sets outlet connections between its custom
controller objects and objects on the user interface, but they can be
made between any objects that can be represented as instances in
Interface Builder,...
Edit2:
I am able to pass the NSPopUpButtons from my MainWindowController to the newRequest method, and I can use the NSPopUpButtons inside newRequest to successfully populate the data.
Edit3:
I know the method in the custom class (newRequest) is working because
I added a NSLog command to print "Test" when the method executes.
But what happens when you log the variables that point to the NSPopUpButtons? With my code in Edit1, I get NULL for the variables, which means the NSPopUpButtons never got assigned to the variables.
Edit4:
If I add an awakeFromNib method to MyData, and inside awakeFromNib I log the NSPopUpButton variables for the code in Edit1, I get non NULL values. That tells me that the MainWindowController's windowDidLoad method is executing before MyData's awakeFromNib method, and therefore you cannot call newRequest inside MainWindowController's windowDidLoad method because MyData has not been fully initialized.
Edit5:
Okay, I got the code in Edit1 to work. The Apple docs say this:
About the Top-Level Objects
When your program loads a nib file, Cocoa recreates the entire graph
of objects you created in Xcode. This object graph includes all of the
windows, views, controls, cells, menus, and custom objects found in
the nib file. The top-level objects are the subset of these objects
that do not have a parent object [in IB]. The top-level objects typically
include only the windows, menubars, and custom controller objects that
you add to the nib file [like the MyData Object]. (Objects such as File’s Owner, First
Responder, and Application are placeholder objects and not considered
top-level objects.)
Typically, you use outlets in the File’s Owner object to store
references to the top-level objects of a nib file. If you do not use
outlets, however, you can retrieve the top-level objects from the
nib-loading routines directly. You should always keep a pointer to
these objects somewhere because your application is responsible for
releasing them when it is done using them. For more information about
the nib object behavior at load time, see Managing the Lifetimes of
Objects from Nib Files.
In accordance with the bolded line above, I changed this declaration in MainWindowController.m:
#interface MainWindowController ()
#property(strong) MyData* data;
...
#end
to this:
#interface MainWindowController ()
#property(strong) IBOutlet MyData* data;
...
#end
Then, in IB I dragged a connection from the MainWindowController data outlet to the MyData Object(the Object I had previously dragged out of the Object Library and onto the doc).
I guess that causes MyData to unarchive from the .xib file and initialize before MainWindowController.
I have a Model Class like this:
Header:
#interface RTSecurityModel : NSObject
{
NSString *code;
}
#property NSString *code;
#end
Implementation:
#implementation RTSecurityModel
#synthesize code;
#end
Then I have my App Delegate:
Header:
#interface RTAppDelegate : NSObject <NSApplicationDelegate>
{
RTSecurityModel *security;
}
#property (assign) IBOutlet NSWindow *window;
#property RTSecurityModel *security;
#end
Implementation:
#implementation RTAppDelegate
#synthesize security;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
security = [[RTSecurityModel alloc] init];
security.code = #"test";
}
Then in my MainMenu.xib I've create a label and in the Bindings Inspector set "Bind To: App Delegate" with "Model Key Path: security.code".
But nothing is showing when I'm starting my application.
I tried soooo many ways to bind this variable, but no one gave success.
Please help me not to hate XCode and Cocoa!
UPD: http://www.experts-exchange.com/Programming/Languages/C/A_3381-Simple-Binding-Cocoa-GUI-Application-without-Outlets.html
Here is the sample how to set Property and Label value by editing the Text Field
But is there a way to edit Label without editing the Text Field? Or without Text Field at all?
UPD2:
You must not create another instance of Object
security = [[RTSecurityModel alloc] init]; // Kill this
Many many thanks to Viktor Lexington
Instead of using security.code as the model path use code. Use the class RTSecurityModel in the value section of the bindings tab instead of the AppDelegate.
Here is a demo project.
Do not bind the Text Field Cell, use the Text Field.
You can check if a value is null if you fill the Null Placeholder with text, will it show that text instead? Then in time of binding the value it null.
To see your RTSecurityModel in the Interface Builder you must let it know your class, it won't look for it.
Add an Object and then set the custom class of it to RTSecurityModel.
Then you can choose this object and set the referencing outlet to the property in the App Delegate.
Assignment will now be directly reflected in the label.
I can think of two ways to solve this programmatically without Interface Builder:
Key Value Coding
// add an observer for the value on the object that has the method below implemented
[self addObserver: self forKeyPath: #"security.code" options: NSKeyValueObservingOptionNew context: NULL];
// method will be called when the observer has 'seen' a value change
-(void) observeValueForKeyPath: (NSString *)keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context {
label.text = ...
}
Use a custom setter for code (#synthesize will still create the getter for you)
- (void)setCode:(NSString *)aString {
label.text = aString;
}
I have a UITabBarController that manages two ViewControllers. The first is a UIViewController that allows the user to change game settings. The second is a GLKViewController that runs the game simulation.
I'm trying to enable the Game ViewController to fetch the settings from the Settings ViewController. I have a Slider on the Settings View that represents "Speed".
I have a reference to the other controller, but I'm unable to expose the variable that backs my Slider properly.
SecondViewController.h
#interface SecondViewController : UIViewController{
IBOutlet UISlider * mySlider;
}
property (nonatomic,retain) IBOutlet UISlider * mySlider;
#end
SecondViewController.m
- (IBAction) mySliderWasMoved:(id)sender;
#implementation SecondViewController
#synthesize mySlider;
- (IBAction) mySliderWasMoved:(id)sender{
};
ThirdViewController.m
NSArray *tmpVCs = self.parentViewController.tabBarController.viewControllers;
UIViewController *tmpVC = [tmpVCs objectAtIndex:1]; //obtain handle to SecondViewController
//NSNumber *mySpeed = tmpVC.mySlider; //doesn't see mySlider
NSNumber *mySpeed = [tmpVC mySlider]; //doesn't see mySlider
I'm new to this, and there are many aspects of my project to learn - so I'm not trying to learn how to manage data at this time. I just need to know how to access an instance variable
As mention on the comments,
Use NSDefault to save the value on slider changed. On the very first time of loading your application, you will want to set a default value.
Use Singleton Object to store value.
We understand that, quoting from you " not trying to learn data persistence at this time. Nor do I need architecture direction.", but the rule of thumb here is that you probably will be able to access the instance variable in some way or the other but i think having the best approach will benefit you greatly.
Just my 2 cent.
Fort the benefit of others: I grabbed a handle to the other class, but I hadn't declared the return type as the correct type of class.
Replace:
UIViewController *tmpVC = [tmpVCs objectAtIndex:1];
With:
SecondViewController *tmpVC = [tmpVCs objectAtIndex:1];
Now I have access to the properties that are specific to the SecondViewController.
I have a textViewController class. I want to set(basically update) the corresponding textView's content from another view controller which I am pushing over the present textViewController. The way I thought I could do this was to have a shared singleton class and have a string property there to contain the text. I have been using the singleton for storing some other content as well and it worked fine till now.
But the text variable in singleton class doesn't hold the content I pass to it from the second view controller and hence the textViewController, after popping the second view controller, displays the old text even after reappearing. I am updating the textView in its viewWillAppear method which is getting called but shows old text content on NSLogging.
What am I missing here? Please suggest a solution, stuck at it for a long time now.
Declaration
Firstly, declare the NSString in your app delegate .h file. It should look something like this:
//YourAppDelegate.h
#import <UIKit/UIKit.h>
#interface YourAppDelegate : NSObject < UIApplicationDelegate >
{
NSString *sharedString; //WE ADDED THIS
}
#property (nonatomic, retain) NSString *sharedString; //AND THIS
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet SomeViewController *viewController;
#end
Now you want to synthesize the object so that the accessor and mutator methods are made for you. This means you don't have to write the setSharedString: and getSharedString methods - we can simply access and mutate the object by making a reference to it. This is how we synthesize it in the .m file:
//YourAppDelegate.m
#synthesize sharedString;
Assigning a Value
When you want to assign a value to sharedString from another class, you must first retrieve the active instance of your application delegate:
YourAppDelegate *appDelegate = (YourAppDelegate*)[[UIApplication sharedApplication] delegate];
The appDelegate object here is your running app delegate instance. To access the sharedString NSString object in the delegate and assign a value, we'd do this:
appDelegate.sharedString = #"some string we want to assign";
For the duration of our application's runtime, "some string we want to assign" is now stored in sharedString in our app delegate.
Retrieving the Value
You'll want to retrieve the value at some point. To do this, again we'll have to get the running instance of our application delegate:
YourAppDelegate *appDelegate = (YourAppDelegate*)[[UIApplication sharedApplication] delegate];
Once we have the running instance, we can then access the sharedString object stored inside it:
NSString *retrievedString = appDelegate.sharedString;
From this point, retrievedString now holds the value "some string we want to assign".
Note:
Everywhere I mention YourAppDelegate, I am referring to your app delegate - the app delegate you have in your project. It'll be related to your project name (look for the file).
How your NSString property for your Text-Variable is defined? Is it a "weak"?