Protocols and delegate trouble in swift - ios

All,
I have create a swift file and put a protocol in it, like this :
protocol PayButtonProtocol {
func enablePayButton()
func disablePayButton()
}
I have made my viewcontroller conform to the protocol like this :
class ViewController: UIViewController, PayButtonProtocol
I have also created the functions in the ViewController so it conforms like this
func enablePayButton() {
println("Button enabled")
PAYBarButton.enabled = true
}
func disablePayButton() {
PAYBarButton.enabled = false
}
And in another class, I have set the delegate and I want to execute the enablePayButton when something is pressed like this :
var delegate:PayButtonProtocol?
and in the function i want to execute one of the functions by :
delegate?.enablePayButton()
but it doesn't execute, what am I missing please ?

More than likely delegate is nil. Add a breakpoint and check the value of delegate before that line executes. Or change the "?" to a "!" and it will crash if delegate is nil, letting you know what's wrong.
Your code in the other class:
var delegate:PayButtonProtocol?
defines a variable named delegate that is of type PayButtonProtocol?.
The variable delegate will contain nil until you assign something to it:
delegate = <someObjectThatConformsToPayButtonProtocol>

Related

How to move data in VC using Delegates?

How can I move the data stored in data into the next VC and append it in my list when the sendDate is tapped ? Here is my code of the sending class :
protocol DataSentDelegate{
func userDidEnterData(data: String)
}
class SecondViewController: UIViewController{
var delegate: DataSentDelegate!
#IBAction func addItem(_ sender: Any)
{
let data = textField.text
delegate?.userDidEnterData(data: data)
}
Here is the code of recieving class :
class SecondPageViewController: UIViewController, DataSentDelegate{
func userDidEnterData(data: String) {
}
#IBAction func sendDate(_ sender: UIDatePicker) {
}
How do I implement list.append(data!) where data holds the value of textField.text
Do you not have to set the delegate in SecondPageViewController to self (normally in ViewDidLoad?
You declared it but don't seem to have assigned it.
You can share data through whole project using Singleton Pattern.
A singleton class is initialised for only once.
Look at these answers:
Swift - set delegate for singleton
What about you just add an array variable in your SecondPageViewController which will hold a list of strings, then append a new string each time sendDate delegate method gets called?
A few other remarks, there is no need to declare your delegate var as implicitly unwrapped if you're using optional chaining anyway, just declare it as an optional. Secondly, because SecondPageViewController is a class, it's better to make your delegate protocol class bound as such: protocol DataSentDelegate: class { func userDidEnterData(data: String) }, thirdly to avoid possible strong reference cycles make your delegate var a weak one.

Trying to understand the implementation of delegates with protocols in Swift

After doing loads of research I am still a little confused about how to use and implement delegates. I have tried writing my own, simplified example, to aid my understanding - however it does not working - meaning I must be a little lost.
//the underlying protocol
protocol myRules {
func sayName(name: String);
}
//the delegate that explains the protocols job
class myRulesDelegate: myRules {
func sayName(name: String){
print(name);
}
}
//the delegator that wants to use the delegate
class Person{
//the delegator telling which delegate to use
weak var delegate: myRulesDelegate!;
var myName: String!;
init(name: String){
self.myName = name;
}
func useDels(){
//using the delegate (this causes error)
delegate?.sayName(myName);
}
}
var obj = Person(name: "Tom");
obj.useDels();
I have read and watched so many tutorials but am still struggling. I no longer get error (cheers guys). But still get no output from sayName.
which demonstrates I must be misunderstanding how delegate patterns work.
I would really appreciate a corrected version of the code, with a simple explanation as to why it works, and why it is helpful.
I hope this helps others too. Cheers.
In Swift you omit the first parameter's external name, so your function call should be delegate.sayName("Tom")
Also, it is dangerous to use an implicitly unwrapped optional for your delegate property, as you have found. You should use a weak optional:
//the underlying protocol
protocol MyRulesDelegate: class {
func sayName(name: String)
}
//the delegator that wants to use the delegate
class Person {
//the delegator referencing the delegate to use
weak var delegate: MyRulesDelegate?
var myName: String
init(name: String){
self.myName = name
}
func useDels() {
//using the delegate
delegate?.sayName(myName)
}
}
Finally, your delegate must be an object, so you can't use a delegate in the way you have shown; you need to create another class that can set an instance of itself as the delegate
class SomeOtherClass: MyRulesDelegate {
var myPerson: Person
init() {
self.myPerson = Person(name:"Tom")
self.myPerson.delegate = self
}
func sayName(name: String) {
print("In the delegate function, the name is \(name)")
}
}
var something = SomeOtherClass()
something.myPerson.useDels()
Output:
In the delegate function, the name is Tom

Cannot assign self as delegate in property initializer

I am getting a strange error message when I try to access self when initializing a property on my class. It seems like my class has a weird type.
This is the error:
Cannot assign a value of type 'ViewController -> () ViewController' to a value of type 'ModelControllerDelegate?'
This is the code, simple example in a playground:
import Foundation
import UIKit
protocol ModelControllerDelegate
{
func modelControllerDidFinishTask()
}
class ModelController
{
var delegate : ModelControllerDelegate?
}
class ViewController : UIViewController, ModelControllerDelegate
{
var modelController : ModelController =
{
let controller = ModelController()
controller.delegate = self
return controller
}()
func modelControllerDidFinishTask()
{
}
}
You are trying to use self when not fully initialised. Might work if you use a lazy initialisation:
lazy var modelController : ModelController = { ...
When initialising a property with a closure like this the closure is run before the instance is fully initialised. This means there are a few things you can't do here:
Access other property values
Use self
Call any instance methods
To get around this you could either initialise modelController entirely in the ViewController's init, or at least defer the setting of its delegate until then.

Using Swift Protocol Inheritance

I am trying to create a delegate that uses traditional polymorphism to compensate for a device being bluetooth LE, bluetooth, etc and can't seem to get the syntax right for casting.
Here is my parent protocol and class:
#objc protocol DeviceDelegate
{
func didConnectToDevice(name:String)
func didFailToConnectToDevice(name:String)
func didDisconnectFromDevice(name:String)
func didWriteData(data:NSData)
func didReceiveData(data:NSData)
}
class Device: NSObject
{
var delegate: DeviceDelegate?
}
Now here is the child class and protocol simplified down:
protocol BluetoothDelegate : DeviceDelegate
{
func didFindService(name:String)
func didFindCharacteristic(name:String)
}
class BLE: Device
{
func someFunc()
{
let bluetoothDelegate = (delegate as? BluetoothDelegate)
bluetoothDelegate.didFindService(UUIDString)
}
}
It throws the following error on the first line of that function:
Cannot downcast from 'DeviceDelegate?' to non-#objc protocol type 'BluetoothDelegate'
This doesn't make sense to me since it should allow casting to a child like a usual object does.
If I put #objc in front of BluetoothDelegate I get the following error:
#objc protocol 'BluetoothDelegate' cannot refine non-#objc protocol 'DeviceDelegate'
Anybody have any ideas on this?
When I copy your code and paste it directly into a playground and add #objc in front of your BluetoothDelegate definition, I get a message on this line:
bluetoothDelegate.didFindService("asdf")
'BluetoothDelegate?' does not have a member named 'didFindService'
Because you have used as?, there is a chance that bluetoothDelegate is nil. You should be using optional chaining here. Replacing with the following line reports no errors in the playground, indicating that you may have done something else in your code that you're not showing us.
bluetoothDelegate?.didFindService("asdf")
Alternatively, you could use this:
if let bluetoothDelegate = delegate as? BluetoothDelegate {
bluetoothDelegate.didFindService(UUIDString)
}
The message you're seeing about DeviceDelegate not being an objc protocol indicates to me that you have written these in two different files and maybe forward-declared DeviceDelegate incorrectly.

Setting the delegate on initialization of object in conforming "header"

I am getting an error trying to set the delegate of my ParseController, which is a property on my VC.
protocol ParseControllerDelegate: NSObjectProtocol {
var parseController: ParseController! {get set}
//TODO:- Instead of this function, i should use a closure, but couldnt get the sytnax right!
func updateUI()
}
class ParseController: NSObject {
weak var delegate: ParseControllerDelegate!
var dataArray:[AnyObject]!
init(delegate:ParseControllerDelegate!) {
self.delegate = delegate
}
Then when I try to set this in my VC "header" I get an error.
var parseController:ParseController! = ParseController(delegate: self)
I am able to set in viewDidLoad with this method, but ideally I would like to set the delegate where it is. The error I get is
Type 'MainVC -> () -> MainVC!' does not conform to protocol 'ParseControllerDelegate'
MainVC is my viewController.
Things I tried:
Casting (self as ParseControlleDelegate)
self()
self!
Im sure it is something simple, but I can't figure out the proper syntax.
Figured it out!
Proper syntax is:
lazy var parseController:ParseController = ParseController(delegate: self)
*Note: I had to remove the delegate requirement from my protocol, as I got a compiler warning that "lazy" isn't allowed on a protocol requirement, and the delegate requirement was not met once I declared it lazy in my VC.

Resources