How do I make connections to custom properties in my nib? - objective-c

I created a custom view. It has a delegate that it will notify when some of its buttons are pressed.
I added this to the view controller's viewDidLoad:
self.myCustomView.delegate=self;
So far everything works fine.
But that's not cool enough. I want to do it the table view style where I can just right drag from the view to the File's Owner and (ta-da!) it's automatically set.

Add the IBOutlet keyword to the delegate property of your class:
#property (nonatomic, assign) IBOutlet id<MyViewDelegate> delegate;
The IBOutlet keyword tells the nib editor to let you make a connection to that property.
You could also say this:
#property (nonatomic, assign) IBOutlet MyView *delegate;
And then IB will only allow you to connect it to a MyView. But a protocol or id is more flexible.
EDIT: One point has been lost due to focus on IB
You said:
I created a custom view. It has a delegate that it will notify when some of its buttons are pressed.
Receiving button events is the role of a view controller, sometimes however a delegate will be used for finer grained control of certain events.
In general dont create a delegate for button presses on a view that is a primary window in which case you should be handling your button events in a ViewController. Buttons sit on a parent view that will forward events up the responder chain (you still need to connect them to a target). Im not saying you shouldn't ever use the delegate pattern for button presses but, buttons have their own connections to view controllers in IB with drag and drop as you wish. But there are situations like yours which are perfectly valid.

Related

Can not link IBaction or IBOutlet

when I try to create an IBOutlet or an IBAction by linking my interface to the header file, I don't get the option to create one.
Yeah, this COULD be a duplicate but I havent found my answer yet on ANY other post!
Thanks :)
#property (assign) IBOutlet NSWindow *window;
- (IBAction)calculateClicked:(id)sender;
#property (weak) IBOutlet NSTextField *ATextField;
#property (weak) IBOutlet NSTextField *BTextField;
#property (weak) IBOutlet NSTextField *CTextField;
I'm not sure what kind of object you wanted to add your outlets/actions to, but one might infer from the presence of the window reference that you're trying to add that to your app delegate. In that case, you just need to make sure that your app delegate appears in the list of objects, and that you've specified the base class for that app delegate:
If, however, you were using some custom controller object, you would drag an generic object from the library to your NIB's list of objects. Then specify the custom controller class for that object (MyController in my example):
Having done that, when you drag your outlets/actions from the window to the assistant editor, in addition to the app delegate, your custom controller object interface/implementation files will be options that you can use.
My original answer was an iOS-centric answer. The above should describe the Cocoa equivalent. I'll keep this original answer here for reference.
Original answer:
In Interface Builder, make sure to specify the base class for the object you're linking the outlets to. If putting these outlets in a view controller, make sure your storyboard's scene has the view controller's class defined. And it's a little easier if your assistant editor is set to "automatic":
The above screen snapshot is relevant if you're using storyboards. If using NIBs, the idea is the same, but you need to make sure you set the NIB's file owner:
If your IBOutlet references are in a UIView subclass, you analogously have to specify the base class for your storyboard scene's view (or the NIB's view).
I've seen Xcode occasionally do this (bug). Closing/reopening Xcode has fixed it for me before.
Also, make sure that your interface file is Class is pointing to this class/header.

How to properly set up NSPopover with separate viewController

I have created an extremely simple test program. It has one button. Clicking the button brings up an NSPopover with a label. That label is on a separate xib file with its own NSViewController.
The Goal is to, when on the main screen, when I click the button, a popover will show the xib file of the viewcontroller. And the label of the xib file should have it's text set to "It works".
Well.. It works, but only on after the second loading of the popover. On the first click of the button, the label still has its old default value. But from the 2nd click and onwards, "It works". Does any one have an idea what can be causing this issue? Its only about 5 lines of code The code can be seen on this repository --> https://github.com/patchthecode/testtest
Call [mainScreenPopoverViewController view]; in - (void)windowDidLoad method. This will load your view into memory.
Before call [mainScreenPopoverViewController view]; (textfield address is 0x0)
You should not use strong property for all IBOutlet.
#property (nonatomic, strong) IBOutlet NSTextField *textField;
Take a look at Resource Programming Guide
From a practical perspective, in iOS and OS X outlets should be
defined as declared properties. Outlets should generally be weak,
except for those from File’s Owner to top-level objects in a nib file
(or, in iOS, a storyboard scene) which should be strong. Outlets that
you create should therefore typically be weak, because:
Outlets that you create to subviews of a view controller’s view or a
window controller’s window, for example, are arbitrary references
between objects that do not imply ownership.
The strong outlets are frequently specified by framework classes (for example,
UIViewController’s view outlet, or NSWindowController’s window
outlet).

iOS Objective C - A pointer to Interface Control on viewDidLoad

i am new into ObjC, unfortunately..
I have created a list and Tool bar at the bottom, with two buttons.
The first button does the list refresh,
the second one should be 'enabled' when you tap on a list item and when clicked it will perform additional work. This requires me to disable this button on start, but enable on didSelectRowAtIndexPath.
I want to grab a pointer to the second button on viewDidLoad method for later purposes.
Something like that would be great:
UIBarButtonItem* m_pButtonA = (UIBarButtonItem*) some_magic_function_to_call;
UIBarButtonItem* m_pButtonB = (UIBarButtonItem*) some_magic_function_to_call;
So i can later call the control method when required.
[m_pButtonRefresh method...]
Is this possible ? Thanks for any input.
In your custom view controller class, create an IBOutlet property, like this:
#property (nonatomic, weak) IBOutlet UIBarButtonItem* m_pButtonA;
#property (nonatomic, weak) IBOutlet UIBarButtonItem* m_pButtonB;
(I'd suggest using more descriptive names)
Then, in Interface Builder you can set those properties to be the Reference Outlet for each of those views (drag from the little (+) to the view control in the left sidebar in IB, and select the appropriate property).
You'll then be able to access those items using code along the lines of self.m_pButtonA. You don't need to manually create the reference to them, as the code will automatically generate them.
This is somewhat similar to the approach you would use when connecting GUI events to methods in the view controller (those would use methods labeled with type IBAction), that are triggered automatically when those events are raised. Both IBOutlet and IBAction are just little hints for Interface Builder (IBAction is actually just another name for void).
Sounds like you're coming from an Android background? You should read about outlets, the equivalent to what you're looking for.
See Apple's cheat sheet, Cocoa Application Competencies for iOS, which links to more thorough documentation if you need it.
Ok, i have found the answer here
Get UIButton reference from viewDidLoad
Long story short:
Just give tag to your button and access your button with tag value.
UIButton *btn = (UIButton*)[self.view viewWithTag:1];
[btn setHidden:YES];

Redrawing an NSView

Sorry if this has been asked before or it's a really dumb question, but I can't figure it out. I have an NSView in my interface, and I have created a subclass of NSView in Xcode. Then using the identity inspector, I set my NSView's class to be the newly created NSView subclass. The view draws fine, but now I need to redraw it to change a string inside the view. I'm pretty sure this has to do with setNeedsDisplay, but what do I send the message to? I don't have a particular instance of my view in the code, since it's in Interface Builder, so what do I do?
Again, sorry if this is dumb. I haven't done much with NSView yet. Ask for more info if you need it. Thanks!
In the view controller subclass you have, add an ivar with type of your NSView subclass. Declare a property on it, and mark it as an outlet.
// ViewControllerSubclass.h
ViewType *myView;
#property(readwrite, assign) IBOutlet ViewType *myView;
// ViewControllerSubclass.m
#synthesize myView;
Now you have an outlet, connect it to the view you designed via IB. To do so, right click in IB on your view controller subclass (the file's owner), you should see the outlet in the list.
Once you have done that, you are now able to send messages to the view in your code.
To mark the view as needing redraw :
[myView setNeedsDisplay:YES];

ios change background on button click

I so far only have the interface builder layout
I'm not clear on the syntax to reference all of these items from the layout
I know that IBOutlet has to be used somewhere, but I need a bit more handholding on what this objective C is doing. Nothing I've read tells me exactly why some declarations start with + and others with -
What I want to do is click a button in my layout, have a modal view pop up and change the background on the entire layout.
so the first step is referencing all these items I've made in the nib. help? (or post a link to more intuitive tutorials that you know about)
So you probably want to create an IBOutlet for your background view. Maybe it's a UIImageView that you can set it's image property based on what the user selects in the modal view. For this you would just declare the UIImageView you have in your IB file
UIImageView *imageView;
and then declare it as a property
#property (nonatomic,retain)IBOutlet UIImageView *imageView;
and synthesize it in your .m file
#synthesize imageView;
Don't forget to release it if you're not using ARC.
Then you can open up interface builder and if you click on your view controller File's Owner and go to the connections inspector you will see there is a new connection there for imageView. Just drag that connection over to your UIImageView in the IB file and that's it. You now have a reference in your code that connects to your UIImageView in IB.
That will allow you to set the UIImageView in your code by typing something like
self.imageView.image = [UIImage imageNamed:theNameTheUserJustPicked];
In order to get the modal view, you need an IBAction to trigger a method in your code so declare one like this in your .h file of your main nib.
- (IBAction)displayViewBackgroundChooser;
and then define it in your .m file.
- (IBAction)displayViewBackgroundChooser {
//present your new view on screen here
}
Then go back to interface builder and click on the File's Owner again. You should see it there in the connections inspector and then you can connect it to a button, for example, that would trigger that method.
Hope this helps to clear things up a bit on IBOutlets and IBActions.
You can make your UI elements created in IB interact with your code by means of IBOutlets and IBActions.
In your case, I would associate an action to the button, so that it is fired when the button is clicked; the action would open a modal view, and you could change the background of that view in the viewDidLoad method of the associated controller.
Here you find a video tutorial about adding an outlet. And here, the same about actions.
About your doubt on + and -, - identifies a normal method defined in a class; + defines a class method, i.e., a method that you can call on the class directly, without having to instantiate it first. Have a look at this S.O. article for more.