OK, so I understand delegates. I am perplexed (in a language design sense) that in some recent Swift work I have encountered delegates that can only be implemented with an "override" qualifier. Specifically "controlTextDidEndEditing" as NSTextFieldDelegate of a NSTextField UI element. (Yes, this is OS X dev work, not IOS).
When implementing this delegate Xcode insists on an override qualifier for the func. If it is a "delegate" function, then what code/functionality up the hierarchy am I overriding and should I care? Inserting super.controlTextDidEndEditing in the implementation simply led to an infinite loop. My comprehension (perhaps faulty/incomplete) of a delegate has been that it defines a signature that the implementation matches.
The context is test panel with an TextField and Label dropped into a ViewController, a trivial test exercise. The only scenario that I can arrive at is that somewhere in the hierarchy above the ViewController some other class is already implementing controlTextDidEndEditing, which leads to the override requirement as soon as I try to implement it, which implies that I am destroying some existing level of functionality. I did experiment with subclassing NSTextField with the same "override" required result.
Can anyone further my education by explaining the ins and outs of this ?
Thanks,
Alan.
This is an example of an obsolete design pattern in older Objective-C code that doesn't map well to Swift. (It's more of a problem with the earliest AppKit code rather than UIKit. Expect Apple to continue to clean up these issues as time goes on.)
controlTextDidEndEditing isn't actually part of the NSTextFieldDelegate protocol (or any other protocols). Instead, it's declared as an Objective-C "informal protocol":
#interface NSObject(NSControlSubclassNotifications)
- (void)controlTextDidBeginEditing:(NSNotification *)obj;
- (void)controlTextDidEndEditing:(NSNotification *)obj;
- (void)controlTextDidChange:(NSNotification *)obj;
#end
An informal protocol is like a class extension without an implementation, and their use dates back to a time when Objective-C didn't support formal protocols or optional protocol methods.
Swift doesn't have informal protocols. Instead, it appears as an extension to NSObject.
extension NSObject {
func controlTextDidBeginEditing(obj: NSNotification)
func controlTextDidEndEditing(obj: NSNotification)
func controlTextDidChange(obj: NSNotification)
}
But Swift doesn't know that this is an informal protocol. As a result, Swift will let you call controlTextDidEndEditing() on any NSObject, even though NSObject does not implement that method.
Likewise, when you implement one of these methods in your own class, Swift will force you to use the override keyword because it thinks you're overriding a method on NSObject, even though that's not the case.
You don't override delegates, you override getters and setters. BUT, classes like UITableViewController conform to the delegate and the datasource, which means they already implement the methods. You override them because, yes, the superclass implements those already.
When you override delegate methods, I don't think you make a superclass call unless the superclass actually performs some function. NSTextField's controlTextDidEndEditing is probably implemented by NSTextField itself as an empty implementation, which is why you need to override.
Related
I have a single window application. Currently I have one xib file (MainMenu.xib) and I have one .swift file (AppDelegate).
If I want to add controls to the UI and assign specific controllers to some of those UI components to to handle additional functionality in a separate file e.g. a NSTextView with a TextViewController - how would I obtain a reference to TextViewController, from within my AppDelegate?
Most tutorials stop short from this and assume that everybody will want to use #IBOutlets to access a controls' properties from the AppDelegate.
I know you can use segues (prepareForSegue) - but my application does not make use of storyboards, and I would like to understand the MVC implementation within cocoa a little better.
Any object can can have its own controller. The AppDelegate is not a holy grail, its just an object which implements methods in the UIApplicationDelegate protocol. Its not a universal switchboard for everything you might wish to connect.
Some of the tutorials do a starting Cocoa dev great disservice by using the AppDelegate as a quick and nasty place to put things. For a storyboard app this all that needs to be contained in the class which conforms to NSApplicationDelegate
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
}
i.e nothing.
A nominal pattern is one screen has one controller but even that isn't true when you use embedding patterns to control subviews within one window. However consider the simple Cocoa Application project template
The ViewController class is a subclass of NSViewController and is where you might be placing the IBOutlet to your NSTextView and some of the logic to do with interacting with it in that context.
import Cocoa
class ViewController: NSViewController,NSTextDelegate {
#IBOutlet var textView: NSTextView!
override func viewDidLoad() {
super.viewDidLoad()
configureTextController()
}
var textController:TextFieldInteractionManager!
func configureTextController() {
//textcontroller can be local var , alternatively inject it into this VC
textController = TextFieldInteractionManager(textView)
}
}
If you have specific interactions that you want to do across the entire project you might want to place these in another class say TextFieldInteractionManager and make that the delegate of the text field. You would pass the text field to the manager class when you construct the view controller.
The hypothetical TextFieldInteractionManager might be created locally or injected in during the setup of the ViewController instance i.e prepareForSegue(segue: NSStoryboardSegue, sender sender: AnyObject?). The possibilities are varied and will depend on the scope of your app and how you wish to manage your references.
My commonly used pattern is to have a Root view controller which passes references down the to the next controller in the chain. YMMV
Dependancy Injection is a good pattern to know about.
Massive View Controller is a good anti-pattern to know about and avoid.
This is what I meant when i said go and get some domain knowledge. Its an expanding tree of stuff to learn about and why your question as its stands is not a good fit for SO.
I just started OS X development with Cocoa, but I got many basic problems.
How can I detect text changed from NSTextField something like onTextChanged() in Java?
Someone said that make delegate, but I can't understand what is delegate, and what it does.
I use cocoa framework with Xcode 5.0.2.
Thanks, and sorry for my bad English :'(
In the class declaration add the NSTextFieldDelegate protocol:
#interface MyView : NSView <NSTextFieldDelegate>
Then in code set:
myTextField.delegate = self;
Now your textfield will send notifications to the delegate, and you can implement whichever delegate function you want (see NSText Delegate Method Implementations in the link below)
What you say you need now is to implement:
- (void)textDidChange:(NSNotification *)aNotification {
//Do stuff here
}
Reference: NSTextField Class
In-spite of writing code you can implement the same thing through binding as well. Just connect your textfield to the delegate of fileowners. Like that below:-
And then implement this below method. So that no need to define NSTextFieldDelegate protocol in header file and no need to set delegatein implementation file through code :-
-(void)controlTextDidChange:(NSNotification *)obj
{
}
I know the question is a bit generic but I guess my issue is generic as well.
I'm developing a small application in my free time and I decided to do it with Cocoa. It's nice, many things works almost automagically, but sometimes it's quite hard to understand how the framework works.
Lately I'm facing a new problem. I want to manage all the windows of the application from a single class, a front controller basically. I have a main menu and an "Import data" function. When I click it I want to show another window containing a table and call a method for updating the data. The problem is that this method is inside the class that implements the NSTableViewDataSource protocol.
How can I have a reference to that class? And more important, which should be the right way to do it? Should I extend the NSWindow class so that I can receive an Instance of NSWindow that can control the window containing the table (and then call the method)?
I may find several ways to overcome this issue, but I'd like to know which one is the best practice to use with cocoa.
PS: I know that there are tons of documentations files, but I need 2 lives to do everything I'd like to, so I thought I may use some help asking here :)
The problem is that this method is inside the class that implements the NSTableViewDataSource protocol.
How can I have a reference to that class?
These two sentences don't make sense, but I think I understand what you're getting at.
Instead of subclassing NSWindow, put your import window's controlling logic – including your NSTableViewDataSource methods – into a controller class. If the controller corresponds to a window, you can subclass NSWindowController, though you don't have to.
You can implement -importData: as an IBAction in your application delegate, then connect the menu item's selector to importData: on First Responder. That method should instantiate the import window controller and load the window from a nib.
In your import window controller's -awakeFromNib or -windowDidLoad method, call the method which updates the data.
Added:
Here's the pattern I'd suggest using in your app delegate:
#property (retain) ImportWindowController *importWC;
- (IBAction) showImportWindow:(id) sender {
if (!self.importWC)
self.importWC =
[[ImportWindowController alloc] initWithWindowNibName:#"ImportWindow"];
[self.importWC refreshData];
[self.importWC.window makeKeyAndOrderFront:sender];
}
I'd like to start a Cocoa app with a ViewController just like the iOS "Single View App" template, but there is no such template (is there a public / open source one that can be used?)
Is it true that for Cocoa apps, we don't really need one, because an NSView can do everything already? We can just put all the event handling in our custom NSView class. Could it be that iOS requires it a lot more because rotation is handled by the ViewController and rotation is usually required? But if we use MVC, then it might be better to always use a ViewController, and if so, is there a standard way, a template, to do it?
The "Controller" in OS X with respect to managing NSViews is the NSWindowController. Though Drummer says that NSViewController isn't very useful, I must disagree - it is useful for splitting up your NSWindowController once it gets too large, and has clear logical divisions in terms of views.
You could have one NSWindowController, and once it gets complicated enough, the NSWindowController could delegate tasks corresponding to specific views to subclasses of NSViewController, and in that respect it is very useful.
In the default templates (if I remember correctly) the AppDelegate takes the role of the window controller, though it isn't technically one. In more complex applications it is a good idea to instantiate a window controller instead.
As long as you don't mix up the controller and view anything can be used. The View should be relegated to just display and basic input handling.
On OS X NSViewController isn't as often used as UIViewController on iOS. One of the reasons is that it's not really useful and lacks a lot of the nice features of UIViewController. There are only a couple of situations where you really have to use them, like when using an NSPopover.
There are several ways to structure your OS X code. One of them is using NSWindowController. You can think of NSWindowController as the equivalent of UIViewController on iOS.
What is the difference between below two methods, both are meant for mapping through Interface builder
- (void) showNYTimes:(id)sender
and
- (IBAction) showNYTimes:(id)sender
Both are working perfectly for my requirement, I am able to map both ways on IB. But which one to opt, is IBAction meant for only readability of code?
Thanks.
IBAction is #defined as void, so as far as Objective C is concerned they're the same; it's meant to be a signal to Interface Builder that this particular method is available to be hooked up to a view. "IBAction - Type qualifier used by Interface Builder to synchronize actions added programmatically with its internal list of action methods defined for a project."
So it's more than just readability; it's a declaration that's meaningful to IB. I'm not sure how you were able to map your (void) method in Interface Builder, though. Only (IBAction) methods have the little circle in the gutter for me.