I'm finding that I'm having to declare the same string value for segue identifiers twice:
Once in code to handle segue logic in my prepare() stubs
Once in the inspector to set segue IDs in the storyboard
Obviously this opens up many potential issues with typos and what not between the two string values.
What I'd like to do if possible is to define my segue IDs once in a plist file and then reference that same definition twice in the the two places listed above. Of course I know it is possible to reference in plist value in Swift but is this possible in the Storyboard attributes inspector?
I don't think that's possible, but I have two alternatives for you:
Use something like R.swift. This tool will parse your Storyboard and create constants you can use in code
Instead of identifying a segue by its identifier, do it by its destination controller.
Example:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller = segue.destination as? MyViewController {
controller.value = self.value
}
}
Personally I use number 2, I very very rarely read the name property of the segue
This one is stumping me, though I know it's going to be simple.
I have multiple ViewControllers, each of which has a table view to display a list of data specific to the controller. Three out of the 4 work perfectly. However, I'm clearly missing something in the forth, because the Delegate methods are never getting called by .reloadData(). No compiler errors, just never calls my delegate methods for some reason.
Here is my class setup including my connected outlet variable:
class performanceViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
//--------------------------------
// OUTLET CONNECTIONS
//--------------------------------
#IBOutlet weak var displayPerformanceList: NSTableView!
I've also implemented the following two delegate functions:
func numberOfRows(in tableView: NSTableView) -> Int {
and
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
but for some reason, neither of these functions are called when I execute my custom function:
func redrawViews() {
self.displayPerformanceList.reloadData()
}
(Note: the .reloadData is wrapped in a function because it will be doing other things as well that I haven't added in yet.)
I added breakpoints in both of the delegate functions, which is how I know they are not getting executed.
I know this is going to turn out to be something stupid that I missed since I have it working in three other custom viewControllers... I just can't for the life of me figure out what I missed...
Any thoughts would be greatly appreciated!
:)
Well, after poking around a bit more and following some tutorials, I found my problem. I completely forgot to link the NSTableView Data Source and Delegate to the controller in the Interface Builder!
Doh!
Leaving this question/answer here in case anyone else gets caught by this. :)
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've read plenty about the How-To about moving data across view-controllers in Swift iOS programming but so far I haven't found a big consensus:
Temporary models (Unnecessary I think for small data)
Variable/Placeholders
Protocols
Others...
The rules about references and pointers in Objective-C may not apply for Swift, so values flying over in memory with protocols may not be the same, or I don't know (that's why I'm asking).
So, in a very simple but well-done manner, if I have a variable say... - result - of String type in a ViewController1 how can I make it available in a ViewController2? I don't need an Strong link to it, just the value.
Which way would you recommend?
Thank you all very much for your answers.
A common way to "jump" from viewController1 to viewController2 is via a storyboard segue. This segue can be performend in several ways: Directly from storyboard (i.e. from a button) or by code, using performSegueWithIdentifier method from a UIViewController.
No matter which way the segue is performed, the method prepareForSegue is called immediately before the segue is performed. In this method you get a reference to the segue's target viewController where you can pass your variable.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController2 = segue.destinationViewController as ViewController2 {
// passing variable from vc1 to vc2
viewController2.result = self.result
}
}
I have a fundamental question related to Cocoa frameworks design patterns.
What's the difference between delegate and data source?
Both of them could use #protocols declaration, but some classes or frameworks are using delegate, and some others are using datasource.
All I can understand from UI/NSTableView is the delegate respond to UI-related events, while the datasource is purely related to the data. But, I don't know any data source implementations outside the UI classes of Cocoa.
Note:
The delegate I mentioned in this question is not always related to UI events.
The data source question has been answered.
The datasource supplies the data, the delegate supplies the behavior.
In MVC, datasource is in the model layer and the delegate is in the control layer.
Actually, on second thought, the datasource is usually controller that is lower down, closer to the model. I don't think I've ever used a model object as my datasource.
The delegate and datasource patterns are largely independent, and orthogonal:
The delegate pattern is very common in Cocoa and allows a delegate (any instance implementing the informal delegate protocol prior to OS X 10.6, or the formal delegate #protocol in 10.6 and later) to modify the behavior of an object instance. This pattern is often used instead of subclassing: instead of subclassing a class to change its behavior, you supply a delegate that responds to the appropriate methods. Classes that use delegates send messages to their delegate at contracted events. The API between class and delegate is defined by the class and is different for each class that uses the pattern, but the API generally consists of messages asking the delegate how to handle a particular event. One advantage of the delegate pattern over subclassing is that a class may implement multiple delegate protocols, allowing its instances to act as delegate for multiple classes. Similarly, an object instance can be the delegate for multiple other objects (hence most delegate APIs pass the object as the first argument to each message in the API). The delegate pattern is not as common in other UI frameworks (though Qt does use the delegate pattern in its Model/View framework), and is not the same as .Net/CLR delegates which are essentially typed function pointers.
The data source pattern is often used by NSView sub-classes in Cocoa that have complex state data such as NSBrowser, NSTableView, NSOutlineView, etc. The data source protocol defines an API that instances of these (and other) classes may use to get the data to display in the view. Although the NSController and Cocoa Bindings architectures have replaced many uses of the data source pattern, it's still common and very powerful. Like the delegate pattern described above, part of its power comes from an object being able to act as the data source for multiple data-source-using instances (and possibly even instances of multiple classes that have different data source protocols). The data source pattern is used commonly in other UI frameworks, such as Qt (in the Model/View framework where the model is analogous to the data source) and WPF/Silverlight (where the data source might be more closely analogous to the view model).
Suppose you had 3 tableviews. For dogs, cats and birds. Tapping on each cell would show a new screen with the enlarged photo of it.
To design this, you'll need to come up with 3 separate datasources for dogs, cats and birds. You basically need three arrays.
However you don't need 3 tableview delegates. Because the behavior of the tableviews are all the same. They all just take present a viewController and fill it with a UIImage. This is only true if you delegate is written in a generic way i.e. there's no dog, cat or bird specific code in the delegate.
Having that said you could abstract out the dog, cat, bird from the data source, but my answer was just a contrived example. Some custom objects are too complex to use the same structure, hence the need to have 3 datasources.
Old answer:
Before answering the question, you must better understand the delegation design pattern:
Let me begin with a question:
By default a TableView is like this:
How does a UITableView know how many cells to present? what to present in each cell?
By itself, it doesn't know.
It asks another class to inform it about the number of cells and what cell to return ( what cellimage, celltitle, cellsubtitle,etc.) values to itself. You usually see a tableView (delegating class) inside a ViewController (delegate class)
This concept of one class asking another is known as delegation!
Now that you know what Delegation is, to answer the actual question of the OP:
It's mostly a HUGE matter of semantic differences.
If you are only to use ( not to create your own protocol) foundation's delegates and datasources then it really doesn't matter for you. However if you intend to write custom protocols then understanding them would help you to write ( and with a higher importance read, refractor) code better.
From a developer's point of view, They both deal with the interaction between the delegat-ing class and delegate class.
Data Source
A data source is almost identical to a delegate. The difference is in
the relationship with the delegating object. Instead of being
delegated control of the user interface, a data source is delegated
control of data. The delegating object, typically a view object such
as a table view, holds a reference to its data source and occasionally
asks it for the data it should display. A data source, like a
delegate, must adopt a protocol and implement at minimum the required
methods of that protocol. Data sources are responsible for managing
the memory of the model objects they give to the delegating view.
In Layman's terms:
DataSource deals mostly with what and usually does it's stuff upon initialization.
Delegate deals mostly with how and feeds you some parameters to give a certain behavior ie if the user clicked this... what should happen? if they swiped...what should happen?
As an example for tableView:
DataSource
What does it have inside of it? What kind of cell am I presenting? cellForRowAtIndexPath.
What is the title of Section? titleForHeaderInSection
How many cells are they? numberOfRowsInSection
And therefore you usually return values. For delegates it's more common to be of type void.
Datasource methods
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell // return a cell ie UITableViewCell
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int // return a number ie an Int
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? // return the title ie a String
Delegate Methods
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
func tableView(tableView: UITableView, willBeginEditingRowAtIndexPath indexPath: NSIndexPath)
func tableView(tableView: UITableView, didEndEditingRowAtIndexPath indexPath: NSIndexPath)
I obviously chose selectively as some datasource methods don't return and some delegate method do return
Delegate
What should I do/what 'form of behavior' should I use after finishing the display of the footer, do you want me to pop an alert?didEndDisplayingFooterView
Am I going to have accessoryType that gives the cell some extra features? accessoryTypeForRowWithIndexPath
From my point of view, a DataSource is an object that doesn't know where the data is, and thus you should provide it. Such as telling an object how many items in a column.
A Delegate, which is a part that object shows to you, must be implemented by your class, because the object knows where the data is, but it does not know how to use it correctly.
To make it short:
Delegate relates to the UI and User actions against the cells and table.
common methods: willSelectRow, didSelectRow, willDisplay, heightForRow, willBeginEditingAt
Data Source deals with the editing, population and displaying of data on
the tableview.
common methods canEditRowAt, commit, titleForHeaderInSection, cellForRowAt, numberOfSections, sectionIndexTitles
Both are Protocol, now the main intension of Protocol is to keep an universal coding practice, or same coding practice for all(to my understanding). Suppose I am creating a tableView without a UITableViewDataSource & UITableViewDelegate, I would create the tableView such a way that you woud not. Thats where Protocol comes, apple created some set of rule or protocol and everybody have to follow that. Now DataSource & Delegate are obviously Protocol, seeing the name you could understand DataSource deals with something like numberOfRowsInSection, cellForRowAtIndexPath, numberOfSections of tableView where some kind of data is being taken/processed, and Delegates are didSelectRow, willSelectRow, heightForRow etc of tableView where its related with some kind of UI change/action. So its just naming convention nothing hypothetical to keep the task separate. As #kubi said earlier: The datasource supplies the data, the delegate supplies the behaviour.