Outlets and instance methods - cocoa

I have a little problem and hope that you can help me.
I want to call a instance method of a subclassed window and set the user interface up there:
//AppDelegate.h
#import <Cocoa/Cocoa.h>
#class MainView;//The main window
#interface DownloadedAppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet MainView*mainview;//the objects are in the same nib, outlet connected with the window
}
#property(nonatomic,retain) IBOutlet MainView*mainview;
#end
.
//AppDelegate.m
#import "MainView.h"
#synthesize mainview;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[mainview launched];//But sometimes this code fails, I don't know why
//launched sets up the interface
}
-(void)dealloc {
mainview=nil;
}
MainView belongs to NSWindow.
Is there something wrong or something to improve? Should I build up the UI somewhere else? Do you know why this code does not work always?

Try putting
[mainview launched];
in
-(void)awakeFromNib {
}

Use the debugger! Is launched even getting called?
Set a break point at the launched call and look at the value of mainview. It is nil? This is because outlets are not guaranteed to be connected until awakeFromNib.

Related

allocating view controller the right way

i am trying to archiv something really simple.
I add a property for a NSScrollView in my ViewController header file called PanelController:
#property (strong) IBOutlet NSScrollView *listurls_fld;
I add the ViewController.h file to my NSObject Interface called "qhandler.h"
#import "handler.h"
#import "PanelController.h"
i have a +(void) function inside the qhandler.m ->
+ (void)do_handle:(NSDictionary *)response
{
PanelController *MyView=[[PanelController alloc] init];
NSLog(#"add moo");
[MyView.listurls_fld setStringValue:#"moo"];
}
which doesn't work...
It does neither work with setAlphaValue or whatever, i guess it's because i am allocating a new instance of PanelController, but as a matter of fact, I tried to change the main instance.
I know it's basic but i have enormous problems using IBOutlets from a viewcontroller, inside an external obj-c file.
Thanks,
john
ViewController.h
id mainDelegate;
ViewController.m
in viewDidLoad oder what function ever triggers after load:
mainDelegate=self;
so i can use [mainDelegate ...:..]; in every file..

Delegate not working, when using a modal presented NavigationController ( iOS 5 - Storyboard )

I have a problem with a protocol.
My "initial View Controller" is a Navigation Controller. On the root page i show an other Navigation Controller in which is View Controller embedded. onclick a segue should be fired...this works perfectly but the delegate method from the "ViewController" is never called.
The image I added is a example how I build the connection between the 2 NavigationControllers with the InterfaceBuilder in iOS 5.
MyViewController.h
#protocol MyProtocol <NSObject>
#required
- (void) myFunction:(NSString *)string;
#end
#interface MyViewController : UIViewController <MyProtocol>
#property (nonatomic, assign) id<MyProtocol> delegate;
#end
MyViewController.m
#import "MyViewController.h"
#implementation PropertyController
#synthesize delegate = _delegate;
- (void) myFunction:(NSString *)string {
[_delegate myFunction:string];
}
- (IBAction) callDelegate:(id)sender {
![enter image description here][1][self myFunction:#"test"];
}
And this is the code for the ViewController which is showing the NavigationController from above
ViewController.h
#import "MyViewController.h"
#interface ViewController : UIViewController <MyProtocol>
ViewController.m
#import "ViewController.h"
#implementation ViewController
- (void) myFunction:(NSString *)string {
NSLog(#"myFunction was called");
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[((MyViewController *) segue.destinationViewController) setDelegate:self];
}
- (IBAction) showModalNavigationController {
[self performSegueWithIdentifier:#"NameFromSegueInInterfaceBuilder" sender:self];
}
I cant find a solution for my problem.
I hope somebody can help me
thank you :)
I see a couple of problems here:
In your storyboard screenshot, you have a second navigation controller. You should not not need to embed your PropertyController in a navigation controller. Instead, have the root view controller segue directly to the PropertyController. If for some reason you do need that navigation controller, then you would need to change your prepareForSegue implementation above, because segue.destinationViewController in this case points to the UINavigationController. So you would need to get that nav controller object, and then send setDelegate to the rootViewController of that nav controller object. But again, only if you decide to keep that navigation controller.
How does MyViewController relate to your ViewController and PropertyController classes? The PropertyController class (or a superclass) needs to have the #property and synthesize statements for the delegate property.
I've been having the same issue, to make it work, I found a work around which xcode does not really like, but it still is working though --> setting your delegate as you do it, makes your navigation controller have your view as delegate, if you NSLog self.delegate in your destination controller it will be null. To prevent this do -->
self.delegate = self.navigationController.delegate;
in your destination controller (viewdidload), it will get the delegation you created on the navigation controller, and allow you yo use it in your destination controller
It is dirty but it's the only way I found. Hope it helps.

Getting around IBActions limited scope

I have an NSCollectionView and the view is an NSBox with a label and an NSButton. I want a double click or a click of the NSButton to tell the controller to perform an action with the represented object of the NSCollectionViewItem. The Item View is has been subclassed, the code is as follows:
#import <Cocoa/Cocoa.h>
#import "WizardItem.h"
#interface WizardItemView : NSBox {
id delegate;
IBOutlet NSCollectionViewItem * viewItem;
WizardItem * wizardItem;
}
#property(readwrite,retain) WizardItem * wizardItem;
#property(readwrite,retain) id delegate;
-(IBAction)start:(id)sender;
#end
#import "WizardItemView.h"
#implementation WizardItemView
#synthesize wizardItem, delegate;
-(void)awakeFromNib {
[self bind:#"wizardItem" toObject:viewItem withKeyPath:#"representedObject" options:nil];
}
-(void)mouseDown:(NSEvent *)event {
[super mouseDown:event];
if([event clickCount] > 1) {
[delegate performAction:[wizardItem action]];
}
}
-(IBAction)start:(id)sender {
[delegate performAction:[wizardItem action]];
}
#end
The problem I've run into is that as an IBAction, the only things in the scope of -start are the things that have been bound in IB, so delegate and viewItem. This means that I cannot get at the represented object to send it to the delegate.
Is there a way around this limited scope or a better way or getting hold of the represented object?
Thanks.
Firstly, you almost never need to subclass views.
Bind doesn't do what you think - you want addObserver:forKeyPath:options:context: (You should try to understand what -bind is for tho ).
When you say "the key seems to be it being the "prototype" view for an NSCollectionViewItem" I think you are really confused…
Forget IBOutlet & IBAction - they don't mean anything if you are not Interface Builder. "Prototype" means nothing in Objective-c.
The two methods in the view do not have different scope in any way - there is no difference between them at all. They are both methods, equivalent in every way apart from their names (and of course the code they contain).
If wizardItem is null in -start but has a value in -mouseDown this is wholly to do with the timing that they are called. You either have an object that is going away too soon or isn't yet created at a point you think it is.
Are you familiar with NSZombie? You will find it very useful.

What's wrong with this Cocoa code?

I'm trying to make a simple Cocoa application using XCode 3.2.3. In interface builder I added NSTextField and NSButton. When I press the button, I want it to clear whatever is in the text field.
I made a new class called AppController.h. This is the contents:
#import <Foundation/Foundation.h>
#interface AppController : NSObject {
IBOutlet id textView;
}
- (IBAction) clearText: sender;
#end
AppController.m looks like this:
#import "AppController.h"
#implementation AppController
- (IBAction) clearText: sender
{
[textView setString: #" "];
}
#end
I connected the button to clearText and the textbox to textView.
The program compiles without error and runs. But when I press the button, nothing happens. Why is that?
Using id for an IBOutlet is a bad practice. Use
IBOutlet NSTextView* textView;
instead.
Please check using the debugger, or putting NSLog(#"foo!"); before [textView setString:#""] to see if the action method is really called.
Another pitfall is that there are NSTextView and NSTextField. These two are different!
The former supports both setString: and setStringValue:, while the latter only supports setStringValue:.
Which object did you use in the interface builder?

Which delegate method should I use to respond to clicks on an NSTextField?

I am trying to respond to a click within a textfield. When the click occurs, I am going to open a panel. My initial thought was to use a delegate method to respond to the click event - but I found that:
This method doesn't work:
(void)textDidBeginEditing:(NSNotification *)aNotification
This method does work, but only when I actually edit the text within the text field, not when I first click it. And - if I edit the text a second time, this method stops working:
(void)controlTextDidBeginEditing:(NSNotification *)aNotification
I could use as much detail as possible - or a code example, ideally. I know that an nstextfield inherits from NSControl, which has a mouseDown event. Is there a similar way to respond to the event with a textfield, also?
Since NSTextField inherits from the NSControl class, it also inherits the -(void)mouseDown:(NSEvent*) theEvent method.
I needed to have an NSTextField call a delegate function upon clicking it today, and thought this basic code might be useful. Note that NSTextField already has a delegate and that in SDK v10.6, the delegate already has a protocol associated with it. Note that if you don't care about protocols, compiler warnings, etc., you don't need the protocol and property declarations or the getter and setter.
MouseDownTextField.h:
#import <Appkit/Appkit.h>
#class MouseDownTextField;
#protocol MouseDownTextFieldDelegate <NSTextFieldDelegate>
-(void) mouseDownTextFieldClicked:(MouseDownTextField *)textField;
#end
#interface MouseDownTextField: NSTextField {
}
#property(assign) id<MouseDownTextFieldDelegate> delegate;
#end
MouseDownTextField.m:
#import "MouseDownTextField.h"
#implementation MouseDownTextField
-(void)mouseDown:(NSEvent *)event {
[self.delegate mouseDownTextFieldClicked:self];
}
-(void)setDelegate:(id<MouseDownTextFieldDelegate>)delegate {
[super setDelegate:delegate];
}
-(id)delegate {
return [super delegate];
}
AppDelegate.h:
#interface AppDelegate <MouseDownTextFieldDelegate>
...
#property IBOutlet MouseDownTextField *textField;
...
AppDelegate.m:
...
self.textField.delegate = self;
...
-(void)mouseDownTextFieldClicked:(MouseDownTextField *)textField {
NSLog(#"Clicked");
...
}
...
If you're building with 10.5 SDK, don't have the protocol inherit from NSTextFieldDelegate.

Resources