How to pass values between 2 NSWindowController - objective-c

I am stuck trying to pass data from one NSWindowController to other one.
I have 2 NSWindowController that has already been instanced and their respective NIB been loaded in screen, in fact firstWindowController load first, get some input from user and do some calculation and save them in several variables and IBOutlets. Upon user action (NSButton) in firstWindowController the secondWindowController load the second Nib window.
Let say:
firstWindowController.h
#class secondWindowController;
#interface firstWindowController : NSWindowController
{
secondWindowController *_secondWindowController;
}
#property long double onedata;
#property (strong) IBOutlet NSTextField *rZab;
#property (strong) IBOutlet NSTextField *xZab;
#end
In firstWindowController.m is the code that instance _secondWindowController, do synthesize in all #property's variables and objects and load the associated nib screen. In the same way, onedata variables and both IBOulets get some values assigned. Omitted for simplicity.
secondWindowController.h
#interface secondeWindowController: NSWindowController
long double newdata;
-(void)getDataFromFirstWC;
#end
secondWindowController.m
#import "firstWindowController.h"
#import "secondWindowController.h"
#import "myAppDelegate.h"
#implementation secondWindowController
-(void)getDataFromFirstWC
{
newdata = 0.0;
newdata = (_firstWindowController.onedata);
// Compilation fails here...
}
#end
This do not compile. The instance of _firstWindowController is not recognized ??.
Use of undeclared identifier '_firstWindowController'
The instance of _firstWindowController has been created in my application delegate already and it is responsible to load the first window nib.
Any help to get this done?. Other answers to more o less similar questions have not help me.

You need to have an instance of your firstWindowController in the secondWindowController. Try this:
in your seconWindowController.h:
#class firstWindowController //<-- add this
#interface secondeWindowController: NSWindowController
{
firstWindowController *fwc; //<-- and this
}
long double newdata;
-(void)getDataFromFirstWC;
#end
in your seconWindowController.m:
#import "firstWindowController.h"
#import "secondWindowController.h"
#import "myAppDelegate.h"
#implementation secondWindowController
-(void)getDataFromFirstWC {
newdata = 0.0;
newdata = (fwc.onedata); //<-- add this and it should work
NSLog(#"newdata is: %f", newdata);
}
#end
As long as I understood your code so far you don't need to create an instance of the secondWindowController in your firstWindowController. Good luck!

Related

In Objective-C, how to make #property's accessible to other classes?

The original question remains below this update:
So further research indicates that my
"...missing setter or instance variable"
log messages are due to an unhinged .xib.
I originally thought that might be the case which is why I went through the process of re-connecting the outlets and properties in the graphic interface builder, but that seems to have been insufficient to repair the connections.
I restored the outlets as properties rather than iVars and reconnected again, still to no avail. So I'm in the process of remaking the .xib's from scratch. Stay tuned for the results.
Original question follows:
Having declared and synthesized properties in parent and sheet classes, and attempted therein to access the properties by their respective class.property names, Xcode rejects the code.
I posted a similar question recently and deleted it after being told there was not enough info to make a response, so I include here below a mini-app which shows how the relevant setup was in the real app of over 2000 lines of Objective-C, which built and ran properly before I attempted to add the Parent / Sheet properties feature.
I've indicated the compiler error messages with a prefix of ////. When I comment out the erroneous lines, the app with its .xib's builds and runs, dysfunctionally of course.
ParentClass.h
// ParentClass stuff belongs in the original main window controller
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface ParentClass : NSObject
{
IBOutlet NSTextField * messageTextField;
IBOutlet NSButton * proceedButton;
}
#property (assign) IBOutlet NSWindow * window;
#property (strong) NSMutableString * parentPropInfo;
- (IBAction) awakeFromNib;
- (IBAction) doCreate:(id)sender;
#end
ParentClass.m
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "ParentDelegate.h"
#import "ParentClass.h"
#import "SheetClass.h"
#implementation ParentClass
ParentDelegate * MyDelegate; // only confirms termination requests
NSWindowController * SheetController;
#synthesize parentPropInfo;
- (IBAction)awakeFromNib {
MyDelegate = [NSApplication sharedApplication].delegate;
MyDelegate.ParentController = self; // BTW, this property assignment works!
SheetController = [[SheetClass alloc] initWithWindowNibName: #"SheetClass"];
messageTextField.stringValue = #"Click Proceed button";
}
- (IBAction)doProceed*emphasized text*:(id)sender {
parentPropInfo = #"Hello!".mutableCopy; // to be read by the sheet
[NSApp runModalForWindow:SheetController.window];
// Sheet is active now until it issues stopModal, then:
messageTextField.stringValue = SheetController.sheetPropInfo; // set by the sheet
////above gets ERROR "Property sheetPropInfo not found on object of type 'NSWindowController *'"
messageTextField.stringValue = SheetController.window.sheetPropInfo;
////above gets ERROR "Property sheetPropInfo not found on object of type 'NSWindow *'"
[NSApp endSheet: SheetController.window];
[SheetController.window orderOut:self];
}
#end
SheetClass.h
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "ParentClass.h"
#interface SheetClass : NSWindowController
{
IBOutlet NSTextField * propTextField;
IBOutlet NSButton * cancelButton;
}
#property (assign) IBOutlet NSWindow * window;
#property NSMutableString * sheetPropInfo;
- (IBAction)awakeFromNib;
- (IBAction)doCancel:(id)sender;
#end
SheetClass.m
#import "SheetClass.h"
#import "ParentClass.h"
#implementation SheetClass
#synthesize sheetPropInfo;
- (IBAction)awakeFromNib {
propTextField.stringValue = self.window.sheetParent.parentPropInfo; // set by the parent
////above gets ERROR "Property parentPropInfo not found on object of type 'NSWindow *'"
sheetPropInfo = #"Goodbye!".mutableCopy; // to be read by the parent
}
- (IBAction)doCancel:(id)sender {
[NSApp stopModal];
}
#end
I can find nothing in Apple documentation or extensive (three weeks now!) online search to offer any insight as to my abysmal ignorance. I apologize for the overwhelming batch of code needed to illustrate my problem! Where shall I obtain the information I need?
The error messages are perfectly clear. Just read them and think about them. Let's just take the first one. You are saying:
messageTextField.stringValue = SheetController.sheetPropInfo;
...and getting this response from the compiler:
// Property sheetPropInfo not found on object of type 'NSWindowController *'
Well, think about the expression SheetController.sheetPropInfo and why the compiler cannot make sense of it. You have declared SheetController as follows:
NSWindowController * SheetController;
So that is all the compiler knows: SheetController is an NSWindowController. Well, sure enough, just as the compiler says, sheetPropInfo is not a property of NSWindowController. It is a property of SheetClass (which is not the same as NSWindowController; it is a subclass of NSWindowController).
If you know that SheetController is in fact a SheetClass instance, you need to tell the compiler that fact. You must either declare SheetController as a SheetClass or cast it down from an NSWindowController to a SheetClass.

Unable to access "center" property of UIView from outside the class

I have an instance of UICollectionViewCell ( lets call it c ).
c has a property child of type B*
#property (strong) B* child;
in B there is a declaration
#property (strong) C* parent;
in C.m I set
self.child.parent = self
In B.m I have code :
position = self.parent.center.x;
For some reason I can not access center property of UIVIew from outside the instance. Is it private ? I looked in UIView.h and in the documentation. I dont see it being private.
Accessing self.parent in B.m is giving me the correct values ...
So why cant I access it ? In C.m
self.center
is working as expected ...
EDIT : With the real code
This is the so-called "C.h"
#import <UIKit/UIKit.h>
#import "UIMovableImage.h"
#interface LetterCollectionCell : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *letterCellView;
#end
This is "B.h"
#import <UIKit/UIKit.h>
#class LetterCollectionCell;
#interface UIMovableImage : UIImageView
{
CGPoint currentPoint;
}
#property (strong) LetterCollectionCell* parent;
#end
This is "C.m"
#import "LetterCollectionCell.h"
#import "LettersCollection.h"
#implementation LetterCollectionCell
-(void)PrepareImage:(int)index Hint:(BOOL)hint Rotate:(BOOL)rotate
{
if ([_letterCellView respondsToSelector:#selector(parent)])
{
UIMovableImage* temp = ((UIMovableImage*)self.letterCellView);
temp.parent = self;
}
}
#end
And here is the "B.m"
#import "UIMovableImage.h"
#import "LetterCollectionCell.h"
#implementation UIMovableImage
- (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event
{
// Get active location upon move
CGPoint activePoint = [[touches anyObject] locationInView:self.parent];
// Determine new point based on where the touch is now located
CGPoint newPoint = CGPointMake(self.parent.center.x + (activePoint.x - currentPoint.x),
self.parent.center.y + (activePoint.y - currentPoint.y));
}
#end
Please note that the LetterCollectionCell's letterCellView is of type UIImageView and not of type UIMovableImage. The reason is that I want to keep this declaration as a placeholder. In the Interface Builder I have two scenes where the LetteCollection is used. In one scene I set the imageview to be of UIMovableImage ( thru Inspector Window ) and at the other I left the image to be of type UIImageView. So the run-time will create the proper class upon different scenes and at the collection I check : if the image has a property "parent" - I set it up. Otherwise I dont.
It works fine, the assignment works just fine.... but the access is not
The only reason you wouldn't have access to the property would be that the class is not aware of it (forward declaration). Therefore, you must have a missing #import "C.h" in B's implementation file.
Perhaps an example is necessary to appease the downvoter, so let's use yours:
Here's what B's header should look like
//Give us the ability to subclass UICollectionViewCell without issue
#import <UIKit/UIKit.h>
//forward declare a reference to class B. We cannot access it's properties until we
//formally import it's header, which should be done in the .m whenever possible.
#class B;
#interface C : UICollectionViewCell
//Declare a child property with a strong reference because we are it's owner and creator.
#property (strong, nonatomic) B* child;
#end
Now C's header.
//import foundation so we can subclass NSObject without a problem.
#import <Foundation/Foundation.h>
//Forward-declare classe C so we don't have to #import it here
#class C;
#interface B : NSObject
//keep an unretained reference to our parent because if the parent and the child have
//strong references to each other, they will create a retain cycle.
#property (unsafe_unretained, nonatomic) C* parent;
#end
Now that that's out of the way, here's the implementation of C that you are most likely using:
#import "C.h"
#import "B.h"
#implementation C
-(id)init {
if (self = [super init]) {
self.child = [[B alloc]init];
self.child.parent = self;
}
return self;
}
#end
Not too bad, but here's the problem:
#import "B.h"
#implementation B
-(id)init {
if (self = [super init]) {
CGFloat position = self.parent.center.x; //ERROR!
}
return self;
}
#end
because C's only declaration that it has a center property (or rather that it's superclass has a center property), and C's type are in the C.h file, B has no knowledge of C's properties without an explicit #import of C.h.
I found the reason.
The whole question was barking at the wrong tree.
In fact, the bug was at the other place and I just kept looking at the "Invalid Expression" int the debugger's watch window.
To sum up : accessing the "center" property worked just find under the circumstances described in the original question. The "Invalid Expression" of the debugger and a bug in a different place made me chase a wrong thing.
I +1d the generally correct answers and comments but can not accept them since it may mislead people.
Thanks to all for the help and the effort
According to the sequence of your question it seems to me that you start with setting the C.m but on that line code the child instance is not set yet.. that self.child = nil so setting self.child.parent = self will give you no result... Accordingly on B.m will not have the access to the parent object...
if i am correct just set your child instance object -- self.child = B* --- before set self.child.parent = self......

No access to global instance (build by factory) on iOS

this is a follow-up question to my last one here: iOS: Initialise object at start of application for all controllers to use .
I have set my application up as follows (ignore the DB Prefix):
DBFactoryClass // Built a DataManaging Object for later use in the app
DBDataModel // Is created by the factory, holds all data & access methods
DBViewControllerA // Will show some of the data that DBDataModel holds
moreViewControllers that will need access to the same DBDataModel Object
i will go step by step through the application, and then post the problem in the end
AppDelegate.h
#import "DBFactoryClass.h"
AppDelegate.m
- (BOOL)...didFinishLaunching...
{
DBFactoryClass *FACTORY = [[DBFactoryClass alloc ]init ];
return YES;
}
DBFactoryClass.h
#import <Foundation/Foundation.h>
#import "DBDataModel.h"
#interface DBFactoryClass : NSObject
#property (strong) DBDataModel *DATAMODEL;
#end
DBFactoryClass.m
#import "DBFactoryClass.h"
#implementation DBFactoryClass
#synthesize DATAMODEL;
-(id)init{
self = [super init];
[self setDATAMODEL:[[DBDataModel alloc]init ]];
return self;
}
#end
ViewControllerA.h
#import <UIKit/UIKit.h>
#import "DBDataModel.h"
#class DBDataModel;
#interface todayViewController : UIViewController
#property (strong)DBDataModel *DATAMODEL;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
ViewControllerA.m
#import "todayViewController.h"
#implementation todayViewController
#synthesize testLabel;
#synthesize DATAMODEL;
- (void)viewDidLoad
{
todaySpentLabel.text = [[DATAMODEL test]stringValue]; // read testdata
}
#end
DBDataModel.h
#import <Foundation/Foundation.h>
#interface DBDataModel : NSObject
#property (nonatomic, retain) NSNumber* test;
#end
DBDataModel.m
#import "DBDataModel.h"
#implementation DBDataModel
#synthesize test;
-(id)init{
test = [[NSNumber alloc]initWithInt:4]; // only a testvalue
return self;
}
#end
the app builds fine, and starts up but the label stays blank. so either the object does not exist (but i guess this would result in an error message), or something else is wrong with my setup. any thoughts?
Two notes:
Your have a shotgun approach to asking questions: everytime you hit a stumbling block, you ask a question and if the answer does not work immediately, you ask another one. You have to spend some energy in between the questions debugging and poking into the code on your own, otherwise you will depend on the external help forever.
Use the common coding style please. CAPS are reserved for macros.
Now to the code:
- (BOOL) …didFinishLaunching…
{
DBFactoryClass *factory = [[DBFactoryClass alloc] init];
return YES;
}
This simply creates an instance of the DBFactoryClass and then throws it away. In other words, it’s essentially a no-op. Judging by the comments in the previous answer you create the controllers using the Storyboard feature. How are they supposed to receive the reference to the data model? The reference isn’t going to show up by magic, you have to assign it somewhere.
I’m not familiar with the Storyboard feature. The way I would do it is to create the view controllers using separate XIB files, then you can create the controller instances in the Factory class and pass them the needed reference to the model. In the end the application delegate would create the factory, ask it to assemble the main controller and then set it as the root view controller for the window. Just like in my sample project. It’s possible that there’s a way to make it work with storyboards, but as I said, I am not familiar with them.

Getting an error while trying to access property from an extern Controller in Xcode 4.2

In a first controller, I create an instance variable for my model, because I want to edit its content from a controller and then access the same object from another controller.
In the second controller, I get an error when trying to access the object:
Property 'levels' not found on object of type FirstController.
Model.h
#imports....
#property (readwrite,copy) NSMutableString *answersString;
FirstController.h
#import <UIKit/UIKit.h>
#import "Model.h"
#interface FirstController : UIViewController{
// some declarations
}
#property (nonatomic, retain) LevelsCompleted *levels;
#end
FirstController.m
#import "FirstController.h"
#interface FirstController(){
//stuff
}
#end
#implementation FirstController
#synthesize levels;
//stuff
- (IBAction)backButton:(id)sender { // This is the changeAnswerString method
if (levels ==nil) self.levels = [[LevelsCompleted alloc]init];
self.levels.answersString=#"1";
[self dismissModalViewControllerAnimated:NO];
}
#end
SecondController.m
#import "SecondController.h"
#import "FirstController.h"
#interface SecondController(){
//stuff
}
#end
#implementation SecondController
-(void) viewWillAppear:(BOOL)animated{
NSLog(#"%#",FirstController.levels.answersString);
// the line above gives me the error "Property 'levels' not found on object of type FirstController
}
#end
Can someone tell me what I am doing wrong here? I have tried to create a FirstController object in the SecondController.h, but this does not give me the same property and hence I do not get the right value of the NSString I modified in the first view.
levels is a instance variable so you cannot access it without instantiating an object first.
You should do something like
FirstController *controller = [[FirstController alloc] initWithNibName:#"First" bundle:nil];
NSLog(#"%#",controller.levels.answersString);
[controller release]
You cannot access another viewcontroller from current viewcontroller directly. Define Level in AppDelagte method and then you can access it from anywhere.
What about moving/adding the LevelsCompleted *levels property to the secondviewcontroller and fill SecondViewcontroller.levels.answerstring when you use backbutton: in you first controller?
As a advice try NSUSERDEFAULT to access it,.,
By Doing Things As Below you can Achive as You want
Ddeclare NSMutableString As in your viewController Class As Global variable.
1) LevelsCompleted.h Class
#import <UIKit/UIKit.h>
NSMutableString *answersString;// In this way this answersString would accessible through out the Application and No Need to make property & synthesiz answersString .
#interface LevelsCompleted : UIViewController{
}
LevelsCompleted.m Class
//First create that NSMutableString object in its LevelsCompleted.m class
#import"LevelsCompleted.h"
#interface LevelsCompleted
-(void)viewDidLoad{
answersString=[NSMutableString alloc]init];//here created answersString object
}
#end //end of LevelsCompleted
2)FirstController.h class
#import <UIKit/UIKit.h>
extern NSMutableString *answersString;
#interface FirstController : UIViewController{
// some declarations
}
#end
FirstController.m class
#import "FirstController.h"
#implementation FirstController
- (IBAction)backButton:(id)sender {
// Because i have created that answersString Global in LevelsCompleted.h class
//we can directly Access and can set the any string Value to that answersString as Below
answersString=#"1";
[self dismissModalViewControllerAnimated:NO];
}
#end
SecondController.h class
extern NSMutableString *answersString;// please do this carefully fro getting access the answersString instance
#interface SecondController:UIViewController{
//stuff
}
#end
SecondController.m class
#implementation SecondController
-(void) viewWillAppear:(BOOL)animated{
NSLog(#"%#",answersString);//here you may access easily.
}
#end
In above code everything would work because i have done the same thing in my app
just try to catch the concept of extern, global variable .

#synthesize is not working and basic operations are not working in Objective-C

I am unsure why this code will not work. When I click a button (action: buttonclick) it should change the two text boxes' (MyTextLabel and MyTextLabel2) text increment value "r" by one. Here is the code:
MainView.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#interface MainView : UIView {
IBOutlet UIButton *MyButton;
IBOutlet UILabel *MyTextLabel;
IBOutlet UILabel *MyTextLabel2;
}
#property (nonatomic, retain) UIButton *MyButton;
#property (nonatomic, retain) UILabel *MyTextLabel;
#property (nonatomic, retain) UILabel *MyTextLabel2;
- (IBAction)buttonclick;
#end
MainView.m:
#import "MainView.h"
#include <stdlib.h>
#include <libc.h>
#implementation MainView
#synthesize MyButton, MyTextLabel, MyTextLabel2;
int r;
- (IBAction)buttonclick {
r++
if(r < 50) {
MyTextLabel.text = #"< 50";
}
else {
MyTextLabel2.text = #"=> 50";
}
}
#end
I have a feeling something's wrong with the way you're using int r. Try putting static int r; at the top of the #interface line in MainView.h and also add, under the - (IBAction)buttonclick; line:
+(void) initialize;
Then remove int r; from MainView.m. Then in MainView.m add:
+(void) initialize {
count = 0;
}
I see two issues:
You can't declare int r where you have it. You should declare it in your interface's variable block (where you declare your button and labels or outside a method) or in the method definition.
The line with r++ isn't ended with a semi-colon.
You don't say in your question what, exactly, isn't working the way you expect it. My guess is going to be that your outlets aren't actually connected properly. You might want to add a log statement to buttonClick like this:
NSLog(#"button click called! MyTextLabel is %#", MyTextLabel);
The point being, mostly, to be sure it isn't nil.
In Objective-C the names of variables and properties must start with a lowercase letter to conform to the Key-Value Coding (KVC) protocol (always myButton, never MyButton). The #synthesize directive relies on this to generate the setters and getters. Thus, for myButton #synthesize will generate -(void)setMyButton:(UIButton *)button and -(UIButton *)myButton.
So, do make MyButton and its colleagues lowercase and see if it helps.
Action methods always have a sender argument, so your -buttonClick: method should be declared like this:
-(IBAction) buttonClick: (id)sender {
}