views:

60

answers:

1

I need to set a variable in Class A from Class B. To test this, I have a while loop running in Class A that continuously prints the variable via NSLog. However, no matter what I try, I cannot get Class B to update the variable in Class A in such a way that Class A can read the changes made by Class B. I am pretty sure I have everything hooked up properly in IB. Here's how I have things set up:

//Class A
@interface AppDelegate : NSObject {
    NSString *teststring;
}
@property(readwrite,nonatomic,retain) NSString *teststring;
@end

@implementation AppDelegate
@synthesize teststring;
-(id)init{
    self = [super init];
    if(self) {
        teststring = [[NSString alloc] init];
    }
    return self;
}
-(void)awakeFromNib
{
    while(1){
        NSLog(@"teststring is %@",teststring);
        usleep(500000);
    }
}
@end

//Class B
@class AppDelegate;
@interface otherClass : NSObject {
    AppDelegate *appdel;
}
-(IBAction)doTest:(id)sender;
@end

@implementation otherClass
-(void)awakeFromNib
{
    appdel = [[AppDelegate alloc] init];
}
-(void)doTest:(id)sender
{
    appdel.teststring = @"Test";
    NSLog(@"Set teststring to %@",appdel.teststring); //this works
}
@end
+2  A: 

You are thinking too much about classes (as seemingly some sort of “department” of code) and not enough about objects, and both your wording and your problem demonstrate this.

You have your instance of otherClass creating a second instance of the AppDelegate class. You already had one AppDelegate instance, which is the actual application delegate (because, I assume, you have it in your nib and you have it hooked up to the application's delegate outlet there); now, in -[otherClass awakeFromNib], you are creating another.

You then tell this second AppDelegate instance to set its teststring property to @"Test", and then you ask your second AppDelegate instance for the value of that property, and your second AppDelegate instance dutifully shows you the value you gave it.

The first instance doesn't have the same value for its teststring property because the otherClass object never gave that instance a value for its teststring property. Note that the variables you define in the @interface section are instance variables, which is why different instances of a class can and usually will have different values in those variables. Properties are likewise per-instance, being usually backed by these instance variables.

AppDelegate A (the real application delegate, created in the nib) and AppDelegate B (created by the otherClass object, not anything's delegate) are two separate instances of AppDelegate, with separate teststring variables.

Thus, the solution: Have the otherClass instance talk to the real application delegate, not an AppDelegate instance that it created itself. You could ask the application for its delegate, or (if the otherClass object is in the MainMenu nib) give it an outlet to the application delegate, just like the application has.

However, piling too much stuff into your application delegate class is bad design; each class should have one specific purpose, and generally should fit neatly within one of the Model, View, and Controller classifications. So, assuming your otherClass object should be a controller, move the property into otherClass and make that object the controller of whatever needs the property.

Peter Hosey
Thanks so much! You helped me realize I was going about this the wrong way, and so I eliminated the second class altogether. I was trying to get values of files dragged onto a second window, but now realize I needed to connect the window's output to AppDelegate (instead of otherClass). I used [sender draggingDestinationWindow] to figure out which window was being dragged onto, and [[sender draggingDestinationWindow] title] to check whether to execute code based on it being the correct window (the code does two things depending on which window gets dragged onto). It now works. Thanks again!
Synthetix