Accessing IB object/controll from a class method - objective-c

Are the objects/controls that you created using IB accessible from a class method?
#Nekto:
#interface CopyController : UIViewController
{
UIActivityIndicatorView *myActivity;
}
#property (nonatomic, retain) IBOutlet UIActivityIndicatorView *myActivity;
+(void) activityIndicator:(BOOL)flag;
#end
This implementation in the .m will not be allowed, the error was "Instance variable'myActivety' accessed in class method".
+(void)activityIndicator:(BOOL)flag
{
if (flag)
[myActivity startAnimating];
else
[myActivity stopAnimating];
}

Yes, they are accessible.
You should add #property IBOutlet ib_object_class *ib_object_name;, open that object settings in IB and set reference outlet to File's Owner by selecting ib_object_name in drop down menu.
Full explanation can be found, for example, here : Creating and Connecting an Outlet

You may be able to connect the outlet to the first responder instead of the file's owner to achieve this, but I don't think you can access it from within a class method since your IBOutlet property is going to be an instance-level variable.
Found something similar for linking actions to multiple first responders here.

Related

View not updating when a message is sent to its view controller

I am having problems updating a view when a message from another class is sent to a ViewController.
Basically I have an application with a single window where different custom views will be swapped out for another. I have an AppController Class that manages this and works fine:
#interface AppController : NSObject
#property (weak) IBOutlet NSView *ourView;
#property (strong) NSViewController *ourViewController;
- (IBAction)changeView:(id)sender;
- (IBAction)start:(id)sender;
- (void)changeViewContoller:(NSInteger)tag;
#end
When a new view is swapped out for another, the ourViewController property will be updated to point to that view's controller class. Every view controller class will have a method all named the same thing, for example "action". This method is supposed to change something on a view.
So the "start" method in AppController class will then call the "action" method on the ourViewController property. To do this I used the objc_msgSend() method:
objc_msgSend(self.ourViewController, action);
Here's the View Controller class definition:
#interface CountdownViewController : NSViewController
#property (weak) IBOutlet NSTextField *label;
- (IBAction)changeLabel:(id)sender;
- (void)start;
#end
I placed an NSLog() in the "action" method for each ViewController, to see if it was working, and it does, however the "action" method is also supposed to change a label's string value, but it does not. If anyone knows why the view is not being updated, that would be extremely helpful. Thanks!
the view is held weak?
TRY making it strong if you need to retain that pointer in this class
btw: ..also why do you objc_msgsend.... use performSelector

One App Delegate, Two Windows

I have a simple Cocoa app. It has two windows, each in a separate xib file:
MainMenu.xib
SecondaryWindow.xib
I have an AppDelegate class, which has a reference to the window in MainMenu.xib. I'm trying to make it have a reference to the window in SecondaryWindow.xib. I'm confused about how to do this. I have made an outlet, as such:
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (assign) IBOutlet NSWindow *secondaryWindow;
#end
Here's the implementation:
#implementation AppDelegate
#synthesize window = _window;
#synthesize secondaryWindow = _secondaryWindow;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSBundle loadNibNamed:#"SecondaryWindow" owner:self];
NSLog(#"_window = %#", _window);
NSLog(#"_secondaryWindow = %#", _secondaryWindow);
}
#end
_secondaryWindow is always (null)
I've add an outlet from in SecondaryWindow.xib connection the second window to the outlet in AppDelegate. What else do I need to do in SecondaryWindow.xib to make the connection complete?
EDIT: added [NSBundle loadNibNamed...]
You need to load it...
By default, MainWindow.xib is loaded by the framework, which creates its own instance of the app delegate.
You should load your second window from your app delegate (try [NSBundle laodNibNamed:#"SecondaryWindow" owner:self]. when you do this, the File's owner will be the application delegate - change the class of the file's owner in interface builder to reflect that and make your connections to it)
Did you set the type of File's Owner in the secondary window's .xib to the type of your app delegate? And did you then connect the window in that .xib to the secondaryWindow outlet of File's Owner?
If you did those things, and if the .xib is properly included in the project and you've specified the name of the file correctly in the +loadNibNamed:owner: message, then your secondaryWindow property should be populated.

Can't access #Property from other class

I'm having trouble accessing some variables in my program.
I have one class called MainMenu.
In the .h file I have declared 2 properties as follows:
MainMenu.h:
#property (nonatomic, retain) IBOutlet NSView *mainView;
#property (nonatomic, retain) IBOutlet NSWindow *theMainWindow;
In another class file, I want to be able to access these 2 variables, current I am using the following code in the other .h class file which does not work, I don't understand what I'm doing wrong:
AppDelegate.m:
MainMenu *theMainMenu = [[MainMenu alloc] init];
[theMainMenu switchViews:theMainMenu.theMainWindow:theMainMenu.mainView];
Here I create an object of the MainMenu class, and invoke a method called 'switchViews' in its definition, I then want to pass it the 2 variables which I'm having trouble accessing.
Any help greatly appreciated.
Thanks in advance everyone.
EDIT: 'switchViews' method shown below:
- (void)switchViews:(NSWindow*)mainWindow:(NSView*)newView {
NSView *dummyView;
[mainWindow setContentView:dummyView];
[mainWindow setContentSize:newView.frame.size];
[mainWindow setContentView:newView];
}
I think the problem is one of 2 different instances of your MainMenu class. If you hooked up your IBOutlets, you must have a blue cube in IB set to your MainMenu class, correct? However, when you alloc init one in your app delegate, that creates another instance of MainMenu that doesn't have those properties connected to anything. Instead, you should also have a blue cube in IB set to your app delegate, and have an IBOutlet in that class that you connect to the MainMenu blue cube in IB.
This might be silly, but did you remember to link your NSWindow and NSView in Interface Builder? Or are you at least manually instantiating them?
My best guess is (assuming there is a MainMenu.xib somewhere), that when you call init, it object is inited but not necessarily loaded. You should try to call your switchViews method in your controllers viewDidLoad or viewWillAppear method to be sure it is all loaded.

Modifying properties of a view controller form another view controller

In my project, there are two view controllers - let's say firstViewController and secondViewController. The second view controller has a button, and I want to make sure when the button gets pressed, the second view controller is telling somehow the first view controller - "hey, I got pressed, do something!", and it will do something, like changing a label. How is this possible to perform? Thanks in advance. Some code :
#interface firstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
#implementation firstViewController
#synthesize textLabel;
#end
#interface secondViewController : UIViewController
-(IBAction)buttonPressed;
#end
#implementation secondViewController : UIViewController
-(IBAction)buttonPressed{
// Hey, I got pressed! Set the text on textLabel to "OK"!
}
#end
This is a very simple case of delegation and protocol mechanism of objective-c..
have a look at this tutorial which will explain you how its done.. you can do this via notification also but that is not usually advised...(because notification is usually used when the receiver is unknown , like in the case of UIDeviceBatteryLevelDidChangeNotification you don't exactly know which view controller wants to know about this.)
I'd first consider what the button press means. Does it change the state of the model?
Say your model is an int, and the button increments it. The view controllers wouldn't message each other about that, they would just both observe the state of the model. (The one with the button could change the state, too).
Thinking about it this way, the solution probably isn't delegation. It's probably notification or KVO.
See the answer to this question: Passing data between two view controllers via a protocol
However, ask yourself if you really need a protocol here. If it is just between this classes or just about the question of accessing data of a class or sending information to a class then that is what the interface of a class is made for.
#interface firstViewController : UIViewController{
UILabel *textLabel; // I personally alway add IBOutlet here too, but I think that is not required.
}
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
And in SecondViewController.m:
#import "FirstViewController.h"
#implementation secondViewController : UIViewController
-(IBAction)buttonPressed{
// You will have to have a properly set instance variable firstViewController
[firstViewController.textLabel setText:#"OK"];
}
#end
So your second view controller needs to 'know' the first one. One way of achieving that is defining
FirstViewController *firstViewController;
as property and set it from wherever the second view controller is created and the first one is already known. How to do that exactly depends very much on the architecture of your app.

When to alloc/init an ivar, and when not to

All,
In Apple's sample code "DateCell"
http://developer.apple.com/library/ios/#samplecode/DateCell/Introduction/Intro.html
the ivar "pickerView" is declared in MyTableViewController.h like this:
#interface MyTableViewController : UITableViewController
{
#private
UIDatePicker *pickerView;
UIBarButtonItem *doneButton; // this button appears only when the date picker is open
NSArray *dataArray;
NSDateFormatter *dateFormatter;
}
#property (nonatomic, retain) IBOutlet UIDatePicker *pickerView;
...
It is synthesized in the class file MyTableViewController.m like this:
#implementation MyTableViewController
#synthesize pickerView, doneButton, dataArray, dateFormatter;
...
When this app runs, I can insert NSLog(#"%#",pickerView) into ViewDidLoad and see that, sure enough, the ivar pickerView is real and has a value. Nowhere, though, does this class alloc/init pickerView. And that's the root of the question: how's it getting done if it's not being done explicitly?
Well, I naively copied this stuff to my code into my RootViewController.h and .m files figuring I could do the same, but pickerView stubbornly remains uninitialized (and my NSLog calls return "(nil)" as its value) no matter what I try short of explicitly alloc/initing it. Certainly RootViewController is being instantiated, or the RootView wouldn't be showing up, right? So shouldn't my pickerView be coming along for the ride just as it does for Apple?
So... do I have to manually alloc/init the pickerView instance variable? If so, where's Apple doing it? Or how are they doing it somehow otherwise?
I think I'm missing something very basic here, but I have no idea what it is. I can't see anything in Interface Builder or XCode that looks different between mine and theirs, but I've got tunnel vision at this point and can't see anything clearly anymore.
Thanks,
Bill
The IBOutlet modifier on this line is the key...
#property (nonatomic, retain) IBOutlet UIDatePicker *pickerView;
IBOutlet is a decorator that indicates that the object will be hooked up/connected/initialised when the corresponding xib (Interface Builder) file is loaded. The sample application you're looking up will contain a UITableViewController is a xib which has a connection to a UIPickerView.
You can either go the route of creating your own custom xib file and wire to an instance of UIPickerView or you can manually initialise the picker yourself.
Interface Builder (nib or xib) treats automatically IBOutlet ivar with connection of components.
IBOutlet is a special keyword that is
used only to tell Interface Builder to
treat an instance variable or property
as an outlet. It’s actually defined as
nothing so it has no effect at compile
time.
Your First iOS Application - The
View Controller Interface
Declaration, Making Connections
Interface Builder User Guide -
Defining Outlets and Actions in
Xcode