Delegate method property to being triggered on conforming class - ios

I have the following protocol
protocol SentenceDelegate: class{
func sentenceDidFinish()
}
I have my SentenceMarkov class conform to the protocol:
class SentenceMarkov : SentenceDelegate{
// foo
// bar
}
I implement the protocol method in my conforming class:
class SentenceMarkov : SentenceDelegate{
//...
func sentenceDidFinish{
//Do something
}
//...
}
I create a property on the class that calls the protocol method called sentenceDelegate :
class otherClass{
//..
weak var sentenceDelegate: SentenceDelegate?
//..
}
I set this property in my first class to self
class SentenceMarkov{
var FirstOne:OtherClass {
didSet { FirstOne.sentenceDelegate = self}
}
var SecondOne:OtherClass {
didSet{ SecondOne.sentenceDelegate = self}
}
init(Ult:OtherClass, Penult:OtherClass){
self.FirstOne= Ult
self.SecondOne = Penult
self.FirstOne.sentenceDelegate = self
self.SecondOne.sentenceDelegate = self
}
//..
}
Finally I call the sentenceDelegate method in OtherClass after its init()
class OtherClass{
func sentenceDone(){
sentenceDelegate?.sentenceDidFinish()
}
}
The problem is that, when I set breakpoints on the above method sentenceDelegate is nil. I am not sure why because I set it, although I could be setting it wrong, I am not sure how to ameliorate that though. Here is the three Swift files include the ViewController where SentenceMarkov is initialized:
https://gist.github.com/ebbnormal/e1cb791dd165a6866e11
https://gist.github.com/ebbnormal/263c9343e403c3a7ac40
https://gist.github.com/ebbnormal/1400e7da024d78ba5ed0

The following works for me:
protocol Greeter: class {
func greet()
}
class Dog {
weak var greeter: Greeter?
}
class DogPound: Greeter {
func greet() {
print("Hi. Welcome to the DogPound!")
}
var dog: Dog {
didSet {
dog.greeter = self
}
}
init(dog: Dog) {
self.dog = dog
self.dog.greeter = self
}
}
let myDog = Dog()
myDog.greeter?.greet() //=>nil
DogPound(dog: myDog)
myDog.greeter?.greet()
--output:--
Hi. Welcome to the DogPound!

Related

How can I assert a delegate is called in my unit test

I would like to asset that the correct delegate method is called depending on the result of a check in my presenter.
Having mocked out my IdentityProvider to return true, how would I write a test to assert delegate?.userIsAuthenticated() is called?
import Foundation
import InjectStory
protocol StartPresenterDelegate: class {
func userIsAuthenticated()
func userNeedsToAuthenticate()
}
class StartPresenter {
weak var delegate: StartPresenterDelegate?
weak var view: StartViewInterface!
private lazy var identityProvider = Dependencies.identityProvider.inject()
init(view: StartViewInterface) {
self.view = view
}
private func checkUserAuthState() {
if identityProvider.isAuthorized() {
delegate?.userIsAuthenticated()
} else {
delegate?.userNeedsToAuthenticate()
}
}
}
extension StartPresenter: StartPresentation {
func onViewDidLoad() {
checkUserAuthState()
}
}
extension StartPresenter {
struct Dependencies {
static let identityProvider = Injection<IdentityProviderProtocol>(IdentityProvider.shared)
}
}
You need to do some trick. Create MockDelegateClass for your protocol StartPresenterDelegate
example:
class MockDelegate: StartPresenterDelegate {
var isUserIsAuthenticatedCalled = false
var isUserNeedsToAuthenticateCalled = false
func userIsAuthenticated() {
isUserIsAuthenticatedCalled = true
}
func userNeedsToAuthenticate() {
isUserNeedsToAuthenticateCalled = true
}
}
then in your test try to do something like that:
func test_MyTest() {
// init your class StartPresenter that you wanna test
var presenter = StartPresenter(...)
var mockDelegate = MockDelegate()
presenter.delegate = mockDelegate
presenter.onViewDidLoad()
XCTAssertTrue(mockDelegate.isUserIsAuthenticatedCalled)
XCTAssertFalse(mockDelegate.isUserNeedsToAuthenticateCalled)
// or change isUserIsAuthenticatedCalled and isUserNeedsToAuthenticateCalled if you expect another states
}
For different states you need different tests, for you it will be the easiest way to test delegate calling.
You have to mock the StartPresenterDelegate as follows too.
class MockStartPresenterDelegate: StartPresenterDelegate {
var userIsAuthenticated_wasCalled = false
func userIsAuthenticated() {
userIsAuthenticated_wasCalled = true
}
}
Inject MockStartPresenterDelegate as the delegate and check that userIsAuthenticated_wasCalled is true
In this way you can confirm the unit test for delegates in Swift apps

Subscribing to a property

I have a singleton service class which maintains a value of heading it gets from the compass. I have a UIView which draws some custom graphics based on this. I'm trying to do something like an Observable in javascript, where my code gets executed when there's a change in the value.
final class LocationService: NSObject {
static let shared = LocationService()
public var heading:Int
public func getHeading() -> Int {
return self.heading
}
Then in my UIView subclass:
var ls:LocationService = LocationService.shared
var heading: Int = ls.getHeading() {
didSet {
setNeedsDisplay()
}
}
I tried also just directly accessing the property via ls.heading but this doesn't get accepted either. It's telling me I cannot use the instance member within the property initialiser. What's a proper swift method of doing this?
Edit:
I've been working with Christian's answer below and some other documentation and now got to here where it all compiles nicely, but doesn't actually work. Here's my delegator and protocol:
final class LocationService: NSObject {
static let shared = LocationService()
weak var delegate: CompassView?
var heading:Int
func headingUpdate(request:HeadingRequest, updateHeading:CLHeading) {
print ("New heading found: \(updateHeading)")
self.heading = Int(updateHeading.magneticHeading)
self.delegate?.setHeading(newHeading: Int(updateHeading.magneticHeading))
}
public func getHeading() -> Int {
return self.heading
}
}
protocol LSDelegate: class {
func setHeading(newHeading:Int)
}
Then in the delegate:
class CompassView: UIView, LSDelegate {
func setHeading(newHeading:Int) {
self.heading = newHeading
print("heading updated in compass view to \(self.heading)")
setNeedsDisplay()
}
}
So I get the print message that the heading has been updated in the headingUpdate function. The print message in the setHeading function in the delegate CompassView never gets displayed.
You can use the delegation pattern and have that class that wants to consume your events implement the functions in your protocol.
protocol MyDelegate {
func setNeedsDisplay()
}
class LocationService: NSObject {
var myDelegate : MyDelegate?
var heading: Int = ls.getHeading() {
didSet {
myDelegate?.setNeedsDisplay()
}
}
...
func assignDelegate() {
self.myDelegate = MyConsumer()
}
}
class MyConsumer : MyDelegate {
func setNeedsDisplay()
{
}
}

delegate in swift 3 does not perform view related codes

In my project I have some delegates that works fine with returning data but I want to add some subview or do any anything in the delegate method on the receiving end nothing happen but the other codes that are in the same method are OK!
My other question is also realated to delegates :
This happens for some delegates. The delegate does not respond but I found a very strange fix on the web and I need to know why this happens and why this fix works!
My First View :
protocol SomeDelegate {
func someMethod()
}
class FirstViewClass {
//in init or didLoad method
var delegate: SomeDelegate?
// THIS DELEGATE WON'T WORK BUT WHEN I ADD THIS LINE IT WORKS FINE( IT STILL HAS THE ABOVE PROBLEM)
self.delegate = SecondViewClass()
//in some custom method
self.delegate?.someMethod();
}
My Second View:
class SecondViewClass : SomeDelegate {
var firstView = FirstViewClass()
// this is in init or didLoad method
firstView.delegate = self
//this is in some custom method
someMethod()
}
A simple working prototype:
protocol SomeDelegate {
func someMethod()
}
class FirstViewClass {
var delegate: SomeDelegate?
}
class SecondViewClass : SomeDelegate {
var firstView = FirstViewClass()
func someMethod() {
print("called via delegate")
}
}
var firstClass = FirstViewClass()
var secondClass = SecondViewClass()
firstClass.delegate = secondClass
firstClass.delegate?.someMethod()

Swift Delegate from Singleton not working

I'm trying to implement SharedInstanceDelegate in App class. I have no idea why the functions under the protocol are not being called.
This is my Protocol and class.
class App {
let sharedInstance = SharedInstance.shared
init() {
self.sharedInstance.delegate = self
}
}
extension App: SharedInstanceDelegate {
func1() { } // this is not executed
func2() { }
}
protocol SharedInstanceDelegate: class {
func1()
func2()
}
class SharedInstance {
static let shared = SharedInstance()
weak var delegate: SharedInstanceDelegate?
private init() { }
func method1() {
self.delegate?.func1() // this is executed
}
}
I believe you meant to make SharedInstanceDelegate a protocol, but you've made it a class. In either case, App does not conform/inherit SharedInstanceDelegate, so it's not clear how this would even compile.
Here is how I would implement your code to work with the delegate:
class App {
let sharedInstance = SharedInstance.shared
init() {
self.sharedInstance.delegate = self
}
}
extension App: SharedInstanceDelegate {
func func1() { } // this will run now
func func2() { }
}
protocol SharedInstanceDelegate {
func func1()
func func2()
}
class SharedInstance {
static let shared = SharedInstance()
var delegate: SharedInstanceDelegate?
private init() { }
func method1() {
self.delegate?.func1() // this is executed
}
}
Still no idea why this was happening, but cleaning the project fixed this. This is very strange. I have other delegates that call successfully.
Your code could work but it depends on how you are calling func1(). Calling it like this:
let testinstance = App().sharedInstance
testinstance.delegate?.func1()
will not work because you are not holding on to the App object. In this case the App object is the delegate, but because its a weak member and no one is retaining it, it gets released right away.
If you call it like this:
let testapp = App()
testapp.sharedInstance.delegate?.func1()
it works. In this case the App object is being retained and is still around when func1() is called.
Either way the way these classes are related is confusing to me. Why have a separate SharedInstance class at all?

Why custom delegate in iOS is not called

I am trying to create a custom delegate using playground in swift. However the doSomething method is not being called through callback.
It seems that delegate?.doSomething() does not fire to the XYZ class doSomething method.
Thanks in advance!
import UIKit
#objc protocol RequestDelegate
{
func doSomething();
optional func requestPrinting(item : String,id : Int)
}
class ABC
{
var delegate : RequestDelegate?
func executerequest() {
delegate?.doSomething()
println("ok delegate method will be calling")
}
}
class XYZ : RequestDelegate
{
init()
{
var a = ABC()
a.delegate = self
}
func doSomething() {
println("this is the protocol method")
}
}
var a = ABC()
a.executerequest()
It seems that delegate?.doSomething() does not fire to the XYZ class
doSomething method.
That is correct. class ABC has an optional delegate property, but the value of
the property is nowhere set. So the delegate is nil
and therefore the optional chaining
delegate?.doSomething()
simply does nothing. Also you have defined a class XYZ but
not created any instances of that class.
If you set the delegate of a to an instance of XYZ then
it will work as expected:
var a = ABC()
a.delegate = XYZ()
a.executerequest()

Resources