Referring to viewcontroller outlets from viewcontroller extension - swift

I have two view controllers SymbolsVC and ItemsVC. Both have a UIActivityIndicatorView which has been outlet by the name of spinner in each view controller like this:
class SymbolsVC: UIViewController {
#IBOutlet weak var spinner: UIActivityIndicatorView!
}
class ItemsVC: UIViewController {
#IBOutlet weak var spinner: UIActivityIndicatorView!
}
Now I need to write a lot of shared code between these view controllers, for example, a function which would start the spinner in its respective viewcontroller. So I have created an extension for UIViewController like this:
extension UIViewController {
func startSpinner() {
spinner.startAnimating()
}
}
However, this gives Use of unresolved identifier 'spinner' error.
What am I missing?
EDIT FOR FURTHER CLARIFICATION: My extension is actually an IAP. This IAP can be called from any number of ViewControllers. When one of the ViewControllers, call the IAP function which is in the extension, it is the flow of the program in that IAP function which determines when to start/stop the spinner. Hence it needs to be done within the extension.

When the compiler sees this:
extension UIViewController {
func startSpinner() {
spinner.startAnimating()
}
}
it thinks every instance of UIViewController in your module contains this spinner property, which of coarse is wrong.
Since as a rule, you can't place regular {set get} properties inside extension, my solution would be placing the spinner inside a base view controller SpinnerBaseVC, which inherits UIViewController.
Then, inherit SpinnerBaseVC with whatever class you want to utilize the spinner property.
class SpinnerBaseVC: UIViewController {
#IBOutlet weak var spinner: UIActivityIndicatorView!
func startSpinner() {
spinner.startAnimating()
}
}
// MARK: Classes which can naturally access `spinner` and `startSpinner`
class SymbolsVC: SpinnerBaseVC {
// Here you can access spinner
}
class ItemsVC: SpinnerBaseVC {
// Here you can access spinner
}

Related

Swift Access Objects In View Controller From Window Controller

I'm just getting into development on mac os and I made a simple app for the touch bar that allows you to change the color (with a nscolorpicker) of a label that is also on the touch bar.
Now I would like to get the same effect on the actual window like so: I change the color using the picker on the touch bar and the color of the colorwell in the window changes as well.
This is the code that I currently have for the touch bar actions:
import Cocoa
#available(OSX 10.12.2, *)
class MainWindowController: NSWindowController {
#IBOutlet weak var cptHello: NSColorPickerTouchBarItem!
#IBOutlet var lblHello: NSTextField!
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
cptHello.color = NSColor.white
setCol()
}
func setCol(){
lblHello.textColor = cptHello.color
}
#IBAction func colorPicked(_ sender: Any) {
setCol()
}
}
This piece of code resides in MainWindowController.swift which is paired with the window controller.
In the view controller, I have a single NSColorWell that I would like to change the color for inside the function "setCol()". I created an outlet in the view controller for it like so:
#IBOutlet var cwHello: NSColorWell!
So ideally what I want to achieve is something like this:
func setCol(){
lblHello.textColor = cptHello.color
ViewController.cwHello.color = cptHello.color
}
Can this be done at all?

WatchKit setBackground Color Crash

After importing UIKit and attempting to toggle around with where to initialize the buttons colors programmatically, I can't seem to figure out why a crash occurs in the class conforming to WKInterfaceController
import UIKit
import WatchKit
class InterfaceController: WKInterfaceController {
#IBOutlet fileprivate var myButton : WKInterfaceButton!
override func willActivate() { // About to be visible to user
super.willActivate()
self.myButton.setBackgroundColor(UIColor.red) // CRASH
}
}
The reason was in unused breakpoints.
Anyway:
Use awake(withContext:) for changing UI:
When creating an interface controller, WatchKit instantiates the class
and calls its init() method followed shortly by its
awake(withContext:) method. Use those methods to initialize
variables, load data, and configure the items in your storyboard
scene. If WatchKit passes a valid object to the awake(withContext:)
method, use the information in that object to customize the
initialization process.
You can't use willActivate() for changing background color etc.:
The willActivate() method lets you know when your interface is
active. Use the willActivate() method to perform any last minute
tasks, such as checking for updates to your content. (Do not use it
for your primarily initialization.)
Also always use weak outlets:
#IBOutlet fileprivate weak var myButton : WKInterfaceButton!
And check that your outlet was connected.

Unable to connect a Custom NSView to its view controller outlet (KPCTabsControl)

I am trying to assign a KPCTabsControl class to a custom NSView. The window view class is MainViewController.
The MainViewController code looks like this:
class MainViewController : NSViewController {
#IBOutlet var myTabsController: TabsController!
#IBOutlet var myButton: NSButton!
//...
}
The TabsController code looks like this:
class TabsController : NSViewController, KPCTabsControlDataSource, KPCTabsControlDelegate {
#IBOutlet var tabsBar: KPCTabsControl?
var titles: Array<String> = []
func tabsControlNumberOfTabs(tabControl: KPCTabsControl) -> UInt {
return UInt(titles.count)
}
//...
}
The form looks like this:
I tried to connect the "Main View Controller" to the "KPCTabsControl" custom view with control-drag. I get the outlet choices: sourceItemView and view. On the other hand, if I try to connect "Main View Controller" to the "+" button, I get the outlet choices: myButton, sourceItemView and view. I don't understand why the "myTabsController" never appears while the "myButton" outlet is available.
Right now, the custom class of the "KPCTabsControl" view is "KPCTabsControl", I tried to enter "TabsController" but it is not listed in the possible choices. And writing it does not work, the value seems rejected and returns automatically to "KPCTabsControl".
What am I missing?
(I'm using Xcode 7.3.1)

Adding NSNotification Observer using swift

I was using this example which explains the use of NSNotification.
In my case, I have a UIViewController in which I have a UITableView. To this tableview I am assigning a dataSource and delegate programatically by instatiating my UITableViewController. So far I have not declared any inits, and thus have been using the simple init() to initialize my UITableViewController. (This UITableViewController is not on the StoryBoard).
class foo: UIViewController{
#IBOutlet weak var fooTable: UITableView!
var fooTableViewController = MyTableViewController()
override func viewDidLoad(){
super.viewDidLoad()
fooTable.delegate = fooTableViewController
fooTable.dataSource = fooTableViewController
}
}
class MyTableViewController: UITableViewController {
override func viewDidLoad(){
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "notificationReceived", name: "TEST_NOTIFICATION", object: nil)
}
}
If I try to add the observer in viewDidLoad() of the UIViewController, it does not work.
So my question is: Does using the NSNotification require the usage of init(coder aDecoder: NSCoder)? If so, then what is the correct way to initialize using this init in swift? How should I be instantiating MyTableViewController in my UIViewController instance foo?
viewDidLoad is only called when the view of a view controller is loaded - in the code you're showing you create a table view controller subclass, assign it as the datasource and delegate of another table view (confusing, as it will already be the datasource and delegate of its own table view), but never actually do anything with the table view controller's view.
This means that viewDidLoad will not be called.
You should probably be adding your table view controller's tableView as a subview and also adding it as a child view controller so that rotation and appearance events are forwarded properly.
Note that the question and answer are nothing whatsoever to do with notification centers or Swift, but just about understanding the view controller lifecycle.
If you want a separate object to act as a datasource and delegate for your table view, great idea, but don't use a UITableViewController subclass. Just create a plain object which conforms to the data source and/or delegate protocols.

UIScrollViewDelegate. scrollViewDidScroll not getting invoked (Swift/Interface Builder/Xcode 6)

I'm trying to hook up a scroll view using Interface Builder, and the UIScrollViewDelegate.scrollViewDidScroll method isn't getting invoked on scroll.
In IB, I have a view controller that uses my PagedScrollViewController as a custom class. In that class, I have:
class PagedScrollViewController: UIViewController, UIScrollViewDelegate {
func scrollViewDidScroll(scrollView: UIScrollView!) {
println("scrollViewDidScroll")
}
}
Unfortunately, that println is never getting invoked. I know that PagedScrollViewController is being connected correctly because if I add a viewDidLoad method, that gets invoked. Is there something extra I need to do to attach the delegate other than setting the custom class?
Turns out I needed to attach the scroll view's delegate to the the controller. Here's what worked for me:
class PagedScrollViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
}