NSViewController delegate? - swift

I'm new to using delegates in Swift, and I can't seem to figure out how to communicate with my View Controller from a different class. Specifically, I call the custom class's functions from my App Delegate, and then from within that custom class, I call a function within my View Controller. My basic setup, following this question, is:
AppDelegate.swift:
var customClass = customClass()
func applicationDidFinishLaunching(aNotification: NSNotification) {
customClass.customFunction()
}
CustomClass.swift:
weak var delegate: ViewControllerDelegate?
func customFunction() {
delegate?.delegateMethod(data)
}
ViewController.swift:
protocol ViewControllerDelegate: class {
func customFunction(data: AnyObject)
}
class ViewController: NSViewController, ViewControllerDelegate
func customFunction(data: AnyObject){
println("called")
}
}
However, delegate is always nil. I am assuming this is either because the ViewControllerDelegate protocol never gets initialized or because I never set the delegate of the actual NSViewController? I know I'm missing something obvious/straightfoward, however I have yet to see what that is.

Your question is hard to answers because you have completely misunderstood the point of a protocol.
A protocol is a type which is used to define functionality. A class that conforms to this protocol provides the specified functionality, by implementing the required methods.
You can not initialize a protocol.
So if your CustomClass looks like this:
class CustomClass {
weak var delegate: ViewControllerDelegate?
func customFunction() {
delegate?.delegateMethod(data)
}
}
Why do you expect that delegate has suddenly a value?
Of course you have to set delegate to something first. The delegate must set delegate. If you want a ViewController instance to be the delegate, it must assign itself to delegate.
This for instance will work.
protocol ViewControllerDelegate {
func delegateMethod(data: AnyObject) //I renamed this because in
//CustomClass you are trying to call `delegateMethod` on the delegate
}
class CustomClass {
weak var delegate: ViewControllerDelegate?
func customFunction() {
delegate?.delegateMethod(data)
}
}
class ViewController: NSViewController, ViewControllerDelegate
var customClass = CustomClass()
func viewDidLoad(){
customClass.delegate = self
customClass.customFunction()
}
func delegateMethod(data: AnyObject){
println("called")
}
}
Read more about delegation here.

Related

Delegate Method is not called in UIButton class

I have a UIbutton class - from which I would like to call an 'adjust constraints' method after the user makes changes on the setting screen. I have created some protocols and all seems in order but it is not calling the method from the subview UIButton after the user closes the Setting Screen.
I have tried some of the other solutions here - that hasn't worked and I think it might be because I am using a UIButton class and I can't reinstantiate it, or call the instantiation? Either way, it never calls the method from the delegate.
Is using protocols the right way to solve this problem and if so, what am I missing?
Basically I have 3 files; the MainVC which I set as my first delegate (it gets triggered from my SettingScreenVC when user is done making changes to Setting Screen):
class MainVC: UIViewController, SettingScreenDelegate {
weak var numButtonDelegate: Buttons_Numeric?
func settingSetButtonConstraints() {
numButtonDelegate?.setupButtonConstraints()
}
}
Then in my Setting Screen I call the MainVC after the user made some changes to their settings:
class MainVC: SettingScreenVC {
weak var delegate: SettingScreenDelegate?
func closeSettings() {
delegate?.settingSetButtonConstraints()
}
}
Then in my Buttons_Numeric class I declare the function and the UIButton class delegate:
protocol numButtonDelegate: class {
func setupButtonConstraints()
}
class Buttons_Numeric: UIButton, numButtonDelegate {
weak var numButtonDelegate: Buttons_Numeric?
required init(coder aDecoder:NSCoder) { super.init(coder: aDecoder)!}
override init(frame:CGRect) {super.init(frame: frame)
self.numButtonDelegate = self
setupButtonConstraints()
}
override func awakeFromNib() {
self.numButtonDelegate = self
setupButtonConstraints()
}
func setupButtonConstraints() {
//SET UP CONSTRAINTS
}
}
Ok so couple of things you need to understand about delegates:
if you create a delegate, you need to conform to the delegate somewhere.
the conforming class should be assigned to the instance of the delegate.
With that in mind lets try to fix the code:
first the settings screen:
protocol SettingScreenDelegate: class {
func settingSetButtonConstraints()
}
class SettingScreenVC {
weak var delegate: SettingScreenDelegate?
func closeSettings() {
delegate?.settingSetButtonConstraints()
}
}
So far so good now the mainScreen should conform to the SettingScreenDelegate and be assigned to its delegate:
class MainVC: UIViewController, SettingScreenDelegate {
weak var button: Buttons_Numeric!
func openSettingsScreen() {
let settingsScreen = ... // the setting screen instanciation
settingsScreen.delegate = self // the MainVC
}
func settingSetButtonConstraints() {
self.button.setupButtonConstraints()
}
}
Now for the last step, the MainVC should have an instance of the button, then the only thing we need to do is call the function 'setupButtonConstraints' from the MainVC which means we do not need the delegate at the button.
class Buttons_Numeric: UIButton {
required init(coder aDecoder:NSCoder) { super.init(coder: aDecoder)!}
override init(frame:CGRect) {super.init(frame: frame)
setupButtonConstraints()
}
override func awakeFromNib() {
setupButtonConstraints()
}
func setupButtonConstraints() {
//SET UP CONSTRAINTS
}
}
You need to assign a value to the delegate variable. I would do it like this if the answer is always self
class Example: SomeDelegate {
lazy var someDelegate: SomeDelegate? = self
}
Otherwise you'll want to do it in the class' initializer or ViewDidLoad.

What's the proper way to subclass a delegate?

I'm trying to learn the delegation process for Swift in Xcode 8.
I can get it working just fine, but have a question about the subclass in my delegate. Normally, in Objective-C, the subclass for this would be NSObject. I'm able to get it working with NSObject and AnyObject. I read a article about not crossing Objective-C because of performance. Does this really matter? If it's not a view or any other type of controller, what's the subclass in Swift for an object?
Is AnyObject the same as NSObject?
ViewController
import UIKit
class ViewController: UIViewController, TestDelegate {
// init the delegate
let theDelegate = TheDelegate ()
#IBOutlet weak var label1: UILabel!
#IBAction func button1(_ sender: Any) {
// tell the delegate what to do
theDelegate.run(add: 1)
}
override func viewDidLoad() {
super.viewDidLoad()
theDelegate.delegate = self
}
// the protocol
func didTest(int: Int) {
label1.text = "\(int)"
print ("Got back from delegate \(int)")
}
}
Object TestProtocol.swift
import Foundation
protocol TestDelegate: class {
func didTest(int: Int)
}
class TheDelegate: AnyObject{
weak var delegate: TestDelegate?
func run(add: Int){
let test = add + 1
delegate?.didTest(int: test)
}
}
There is no reason to subclass AnyObject, since everything is an AnyObject just by existing (like object in Java).
NSObject is the old base class in Obj-C, so if you are wanting to have your protocol or class be seen in Obj-C code it must either be marked #objc or it must subclass NSObject.
So unless you are also using Obj-C in your program, then you don't need to subclass NSObject.
Look at
Swift 3: subclassing NSObject or not?
https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

ViewController does not conform to protocol xyzDelegate

// QuizPopUpViewController.swift
#objc protocol QuizPopUpViewControllerDelegate {
func ApplyNowToSendBack()
}
class QuizPopUpViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
weak var delegate: QuizPopUpViewControllerDelegate?
}
// giving event from here
if isError == false {
self.delegate?.ApplyNowToSendBack() // delegate method
}
}
// Another Viewcontroller
class ShortlistViewController: ParentViewController , QuizPopUpViewControllerDelegate {
}
When i add QuizPopUpViewControllerDelegate to ShortlistViewController, i get the following error:
Type "ShortlistviewController" does not conform to protocol QuizPopUpViewControllerDelegate
The problem is exactly what the error description is suggesting. You need to make your class conforming on QuizPopUpViewControllerDelegate delegate.
To do so, you need to declare the function, what is in QuizPopUpViewControllerDelegate.
// Another Viewcontroller
class ShortlistViewController: ParentViewController , QuizPopUpViewControllerDelegate {
func ApplyNowToSendBack() {
// do something with the callback.
}
}
To avoid asking such questions in the future, i would recommend to read more about the delegate pattern in Swift.

Delegation on a class in Swift

I have a delegation/initialization problem I can't seem to solve. Basically I have a storyboard with a few View controllers. Inside the storyboard there is this "View controller" which consists of a UITableview that I have connected with a DeviceListViewController class so that it populates the information. In here I have declared the following protocol:
protocol DeviceListViewControllerDelegate: UIAlertViewDelegate {
var connectionMode:ConnectionMode { get }
func connectPeripheral(peripheral:CBPeripheral, mode:ConnectionMode)
func stopScan()
func startScan()
}
and inside the class itself I have a init method like this (which is probably wrong but I didn't know what else I could do at this point):
convenience init(aDelegate: DeviceListViewControllerDelegate) {
self.init()
self.delegate = aDelegate
}
Then there is this second class that is not attached to any view controller called BLEMainViewController. It should be a singleton handling all the bluetooth actions. This means I should be able to delegate some stuff between DevicelistViewController and BLEMainViewController.
In the BLEMainViewController I have inherited the DeviceListViewControllerDelegate:
class BLEMainViewController: NSObject, DeviceListViewControllerDelegate {
var deviceListViewController:DeviceListViewController!
var delegate: BLEMainViewControllerDelegate?
static let sharedInstance = BLEMainViewController()
}
override init() {
super.init()
// deviceListViewController.delegate = self
deviceListViewController = DeviceListViewController(aDelegate: self)
}
The problem is that BLEMainViewController is not attached to any View Controller (and it shouldn't IMO) but it needs to be initialized as a singleton in order to handle all the BLE actions. Can anyone point me in the right direction (with an example preferably) on how to work around this?
I think you simply used wrong code architecture.
The BLEManager is a shared-instance, you can call it from everywhere, set it properties, and call its methods.
Its can delegate your view-controller with any predefine events you will add to its protocol and provide proper implementation
Here is some code, hope it helps
protocol BLEManagerDelegate{
func bleManagerDidStartScan(manager : BLEManager)
}
class BLEManager: NSObject {
static let sharedInstance = BLEManager()
var delegate: BLEManagerDelegate?
var devices : [AnyObject] = []
func startScan(){
delegate?.bleManagerDidStartScan(self)
//do what ever
}
func stopScan(){
}
}

Passing variables from two NSWindows in Swift

I am trying to update a label in an NSViewController from a NSWindowController.
Here is what I've done.
Created a protocol:
protocol PopoverProtocol: class {
func SearchForIt(Query:String)
}
Created a function to update the label in the NSViewController
class PopoverController: NSViewController, PopoverProtocol {
#IBOutlet weak var Label: NSTextField!
func SearchForIt(Query:String){
Label.stringValue = Query
}
}
Called the protocol and function from the NSWindowController
class TutorialViewController: NSWindowController, NSSearchFieldDelegate {
weak var responder : PopoverProtocol?
#IBAction override func controlTextDidChange(obj: NSNotification) {
PopoVer.showRelativeToRect(SearchField.bounds, ofView: SearchField, preferredEdge: NSRectEdge.MinY)
responder?.SearchForIt(SearchField.stringValue)
}
}
However nothing is happening. I am not getting any error messages, the function SearchForIt is just not being called.
Any ideas on what I am doing wrong ? Thank you for your help !
A protocol is adopted by a class as you did in your second block of code above. Now your view controller has to implement the SearchForIt method and then your view controller can take the call, not a separately defined object.
In your controlTextDidChange, replace responder with your viewcontroller instance.