get instance from Controller object in NSImageView (cocoa) - objective-c

I'm new to Objective-C.
I had make a little application with an Image Well (NSImageView) and some Buttons.
To receive the actions from the Buttons and Labels. I created a Class named "Controller". I have connected this class using the "Object" object to the InterfaceBuilder file.
For the Image Well, I created a class to inherits from NSImageView (DImageView) and set this class as class for the ImageWell (using the interfaceBuilder)
In this class I had overwritten the mouseDown Method:
//Class DImageView
- (void) mouseDown:(NSEvent *)theEvent
{
NSLog(#"Test");
}
Now I want to call an method which is defined in the class Controller from this method.
But if I create a new instance of the controller object with [[Controller alloc] init]. I'm creating an new instance and can't access the IBOutlets in the Controller class right?
How can I solve this problem?
Thanks for the help ..

Link it via xib file:
And consider overriding acceptsFirstResponder too, otherwise you will not get any mouse event.

Related

Objective C : Custom class in identity inspector creates a new object of that class?

In a storyboard when I add a new view (for example a TableView) I can select a class in the "Custom class" field in the identity inspector.
If I understand the rule of this class, I expect this class "answer" to messages sent to my tableview (i.e. this class is my table viewcontroller) and when I run my project it seems to do what I want.
My question is: To do this, I expected my Xcode automatically instantiates an object of my controller class and "link" this object to my GUI in storyboard.
However, I expected that if I override the init method of my controller class with
-(id) init
{
self=[super init];
NSLog(#"object controller created automatically");
return self;
}
I have the string in output when is created my controller object.
Instead, I have no output.
Why is this happenig and what is wrong with the code?
UIView set up by storyboard never called init.
Instead, you should use - (void)awakeFromNib in which your outlet has been ready to use.
- (void)awakeFromNib {
[super awakeFromNib];
NSLog(#"object controller created automatically");
}
From awakeFromNib documentation:
Objects that conform to the NSCoding protocol (including all subclasses of UIView and UIViewController) are initialized using their initWithCoder: method. All objects that do not conform to the NSCoding protocol are initialized using their init method.
If I understand you question you want a message to be printed whenever your viewController is initialised.
Why dont you write the code in the viewDidLoad?
Like:
In your YourControllerClass.m
-(void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Controller created");
}
Now set the class of the controller in the storyboard to YourControllerClassand the message should be printed whenever your controller is created.
Cheers
P.s.: If you still need help or got a question, please write a comment.

Cocoa - awakeFromNib is not called

I have an MainMenu.xib, and AppController is its file owner. I added -(void)awakeFromNib method which worked fine. Now, rounds of fixings down the road awakeFromNib stopped being called, and I can't figure out why. It owns the xib, so it should be called when it is unarchived. What's going on?
EDITED:
Well, I renamed awakeFromNib to something, and called that from init... that worked. Still confused as to why awakeFromNib is not. I also have a +(void) initialize method in there, could that be messing something up?
- (id)init {
self = [super init];
if (self) {
[self something];
}
return self;
}
-(void)something {
NSLog(#"yup");
}
Setting the class name of the File's Owner in the nib is only so you can tell Xcode what object's outlets and actions to show you so you can hook things up. It doesn't affect what object is actually the File's Owner when the app runs and the nib gets loaded.
The MainMenu nib's File's Owner is always the application object, no matter what class name you set for the FO in Xcode's inspector. Setting it to any class name but NSApplication[1] is wrong.
When you run your app, you should find error messages in the Console about any outlets or actions of the AppController that you tried to connect. They couldn't be connected because the application object doesn't have them.
Change the class name back in the nib editor, and create your AppController as a custom object in the MainMenu nib.
Well, I renamed awakeFromNib to something, and called that from init... that worked.
That means that init is getting called, which means you're calling it. That's a valid alternative to creating it in a nib, though you shouldn't override awakeFromNib if it's not in a nib or owning one.
Your choice: Continue creating the AppController using alloc and init, or remove that code and create it in the MainMenu nib instead.
[1]: Or, if you've subclassed NSApplication and changed the principal class of your app bundle to be that subclass, the name of that subclass.

Subclassing UIBarButtonItem

I'm trying to make a subclass of the UIBarButtonItem class. The button is added in the nib file and I set its class to my custom class in the interface builder. Now if this was a UIView class or subclass I would have override the - (id)initWithCoder:(NSCoder *)decoder method to start the extra customization, however UIBarButtonItem lacks such a method. I tried to override its -(id)init method but with no success, it doesn't get called. My question, where should I start my customization? What method do I need to override?
It's because you use IB. When you create an object in IB it does not call the init method for the class, it uses the archive version of the object. So to make custom initializations use this method instead:
-(void)awakeFromNib{
//initialize here
}

Assign button from another class to a current class selector with cocoa

I instantiate a class and then I try to change the selector of the instantiated class button:
WebViewController *newtab = [[WebViewController alloc] initWithNibName:#"NavigatorNoBottom" bundle:nil];
[[newtab tabsButton]setAction:#selector(addtabs:)];
The button tabsbutton is an outlet of the WebViewController class which is directly linked in interface builder.
The method -(void)Addtabs:(id)sender is a method in my current class.
But it seems that this code does not work, my button is here but it does nothing when I click on it .
If you need more context don't hesitate. I know this is something maybe very simple but I just bug at it....
Note that -initWithNibName:bundle: does not load the nib file immediately. This means that right after sending it you cannot expect your outlets to be set.
In that line where you send -setAction:, your tabsButton outlet is probably nil.
If WebViewController inherits from NSViewController, you can place that line that sets the action in the -loadView method of your WebViewController class to make sure the nib file has been loaded and all outlets are set:
- (void)loadView {
[super loadView];
[tabsButton setAction:#selector(addtabs:)];
// or [self.tabsButton setAction:#selector(addtabs:)];
}
Alternatively, if you don’t want to do this inside the view controller, you can do the following in an arbitrary class:
WebViewController *newtab = [[WebViewController alloc] initWithNibName:#"NavigatorNoBottom"
bundle:nil];
[newtab view];
[[newtab tabsButton]setAction:#selector(addtabs:)];
By sending -view to the view controller, you force it to load the nib file, hence the tabsButton outlet will have been set right after that.
Note that you can set the action in any class since a selector is not tied to a class. Also note that, since you haven’t set a target, the action will follow the action chain.

Update UI from another Class Method - Cocoa

I would like to update the UI in my application from the AppDelegate, but whenever I call it as so:
Controller *object = [[Controller alloc] init];
[object methodHere];
It doesn't seem to update the UI. What am I doing wrong here? I have put in a NSLog to see if it was being called, and it is. Here is a sample project that shows the error.
Edit: Can someone just show me what to change to the project I provided. I just don't know what to type into my project so that I can change the value of a simple NSTextField from another class.
When you write [[Controller alloc] init], you are not accessing the Controller object that is in your nib. You are creating a new Controller object that is unconnected to anything else in your application.
Remember, every Controller object is not the same any more than every NSArray is the same. Just because you made one Controller in your nib that's connected to an NSTextField does not mean some random Controller that you just created shares that controller's connections.
What you need to do is give the delegate a reference to the Controller that's in the nib.
This is really simple, and Chuck's comments basically explain what you need to do, but I will lay out the code explicitly for you. In testAppDelegate.h:
#interface testAppDelegate : NSObject <NSApplicationDelegate> {
NSWindow *window;
// You can make an IBOutlet to any kind of object you
// want; it's just a way for you to get a reference
// in code to an object that has been alloc'd and
// init'd already by the xib mechanism.
IBOutlet Controller *controller;
}
Then go into your xib in InterfaceBuilder and hook up that outlet from your Test App Delegate object to your Controller object (these objects are already present in the xib).
In testAppDelegate.m:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// This is the key:
// _Don't_ alloc/init a new controller object. The
// objects in your xib are allocated and initialized
// by virtue of being in that file. You just need to
// give your AppDelegate a pointer to it, as above.
[controller setTextValue:#"hello"];
}
It's being called all right, but it's not connected to the interface. There should be a view controller of some sort defined in your appDelegate.h file, call the method on that object instead.
Update for more detail:
One way you could pull this off would be to simply save the Controller when you originally create it (and not release it until later.)
Simply put your own controller object into your .h file
Controller* myController;
And when you create the new view controller you want to flip to, simply set myController to reference that object, and later when you want to update the UI, simply call
[myController methodHere];
A bit clumsy, but it works. Just don't forget to release myController when you're done with that view.
The other idea I'd suggest looking into would be to alter the method you're passing to your delegate. That is, instead of having the method as
-(returnType)callDelegateToDoSomething;
put it in as
-(returnType)callDelegateToDoSomething:(id) sender;
You call the new method the same way, but your controller should automatically pass itself as an argument. Then, inside the method, simply use
[sender methodHere];
and it should hopefully work. (You may need to play around with it a little. I'm not an expert on delegates or the sender argument, but it's worth a shot.)