Passing self into initializer as delegate within own initializer - swift

might be a silly question, but I'm trying to understand better why I can't do this. I recall this working in Swift 5.6.1, but I recently updated to Swift 5.7.2.
Before asking, I want to note that I did see this question: Swift passing self as argument in class init, but it didn't quite answer my question. Or maybe I just want to see if these are the only solutions...
I have a couple of classes that's something like this.
class Bar {
weak var delegate: FooDelegate?
init(delegate: FooDelegate) {
self.delegate = delegate
}
}
class Foo: FooDelegate {
var bar: Bar
init() {
self.bar = Bar(delegate: self)
}
}
Before I updated, I don't remember this throwing any errors. Now I'm getting the error
Variable 'self.bar' used before being initialized.
Is there a way to set this up so that I'm passing the delegate correctly?
Thanks all!

You can solve this by breaking it up in two steps, create the Bar object and then set delegate
init() {
bar = Bar()
bar.delegate = self
}
Of course this requires a new init for the Bar class

Related

Should I use a bridge class for setting my delegates for my ViewController?

I can simply use delegates in my views or viewControllers, no issue there, I though that would be nice if I use a bridge class for my entire app for more control on delegates, like this:
protocol MyDelegate {
func work1()
func work2(value: Int)
func work3(value: String)
}
class MyClass {
lazy var work1Delegate: MyDelegate? = nil
lazy var work2Delegate: MyDelegate? = nil
lazy var work3Delegate: MyDelegate? = nil
}
let sharedMyClass: MyClass = MyClass()
And were I need to take action I simply use this on viewDidLoad and also conforming to MyDelegate as well:
sharedMyClass.work1Delegate = self
sharedMyClass.work2Delegate = self
sharedMyClass.work3Delegate = self
I found 2 downside in my method, first I have to type 3 line of codes like this for example for my ViewController, in the real app it would be like 10 function and 10 lines like this:
sharedMyClass.work1Delegate = self
sharedMyClass.work2Delegate = self
sharedMyClass.work3Delegate = self
And second if I just need func work2(value: Int) for another view or viewController I have to have those other 2 function as well because of conforming to my protocol.
I wanted show what I am doing and asking for solving this 2 issues, having a bridge class is a must for me, but I would like to solve those 2 minor issues.

Swift passing two delegates by condition

Currently, I am converting Obj-C code to Swift.
Setup:
Protocol A
func methodA()
Protocol B
func methodB
Class C
func passing() {
if deleagteA?.methodA?() {}
else if delegateB?.methodB?() {}
}
Originally in Objective-C, it were handled by if delegate is conforms A pass methodA, else if conforms B protocol then pass methodB. Since Swift no have or not need responseToSelector method, and came up with above implementation. Is there better way to write on Swift instead having empty block?
From what you've posted, it's not clear if your protocol methods are optional or not. This will work either way.
(delegateA?.methodA ?? delegateB?.methodB)?()
And if you've got a lot of them, you can put them into an array.
[delegateA?.methodA, delegateB?.methodB, delegateA?.methodA, delegateB?.methodB]
.compactMap { $0 }
.first?()
If you want to have a solution more similar to the old one with only one delegate property you can do like this
class C {
var delegate: Any?
func passing() {
if let delegate = self.delegate as? A {
delegate.methodA()
} else if let delegate = self.delegate as? B {
delegate.methodB()
}
}
}
It's a little bit more code but you don't need 2 properties and avoid the risk of assigning 2 delegates at the same time
It turns out ?? Nil-Coalescing Operator is the fix for this case.
delegateA?.methodA() ?? delegateB?.methodB()

Simple swift delegate in swift playground

I'm very new to Swift and programming in general, a bit of Fortran 77 way back, and more recently some simple programming of microcontrollers. I'm working through the basics and all was well until i came across something that i just can't quite get to grips with - delegates. All the online posts don't quite get the concept across, at least for me, so to give myself something that i can refer back to, i've set up a basic template shown below in playground. If i run the code below it works and prints "Something done" to the terminal, but if i make the protocol a "class" protocol ie "protocol SomeDelegate: class {" and make the "var delegate" a "weak var delegate" as recommended in various posts, it doesn't work - what am i doing wrong?
import UIKit
protocol SomeDelegate {
func DoSomething()
}
class MyViewcontroller: UIViewController, SomeDelegate {
func DoSomething() {
print("Something done")
}
}
class OtherClass {
var delegate: SomeDelegate?
func DoSomething() {
delegate?.DoSomething()
}
}
var myVar = OtherClass()
myVar.delegate = MyViewcontroller()
myVar.DoSomething()
It doesn't print because the delegate is nil right after you set it. The reason for this is simple: no instance owns it (the reference count is zero). No one owns delegate because you declared it a weak property of OtherClass. Try establishing an ownership, e.g.
var myVar = OtherClass()
let viewController = MyViewController()
myVar.delegate = viewController
Even though delegate is weak, it will now print Something done again.
Declaring delegates as weak makes sense because it prevents circular references causing delegate to never be release in memory – that's a whole different story though – check how reference counting works, then you will understand why this is a good practice.

Delegate property with different type in Swift

Ok so we have UIScrollView declaration:
protocol UIScrollViewDelegate: NSObjectProtocol { ... }
class UIScrollView: UIView {
...
weak var delegate: UIScrollViewDelegate?
...
}
And then UITableView with delegate variant?
protocol UITableViewDelegate: NSObjectProtocol, UIScrollViewDelegate { ... }
class UITableView: UIScrollView {
...
weak var delegate: UITableViewDelegate?
...
}
How Apple did this? When I do my
protocol MyScrollViewSubclassDelegate: NSObjectProtocol, UIScrollViewDelegate { ... }
class MyScrollViewSubclass: UIScrollView {
...
weak var delegate: MyScrollViewSubclassDelegate?
...
}
I get Property 'delegate' with type 'MyScrollViewSubclassDelegate?' cannot override a property with type 'UIScrollViewDelegate?'.
I stumbled upon this a few times and the only work-around I found was just calling my property something else like customDelegate or whatever you like.
It would be neat indeed to be able to just call it delegate but hey!
MyScrollViewSubclass has the delegate property of UIScrollView because it's subclass of UIScrollView.
As delegate is already defined by UIScrollView, you cannot define the same property name with a new type.
Change the variable name delegate to myDelegate (or something else) and it should work.
I got this working but I do not like the solution very much since it throws away type checking.
What I did was this. In my base class I declared the delegate as
weak var delegate: AnyObject? = nil
Then, when I want to call a method on the delegate I do
if let delegate = self.delegate as? MyBaseClassProtocol { delegate.myMethod() }
In my subclass I can then also do the same kind of thing
if let delegate = self.delegate as MySubclassProtocol { delegate.mySubclassMethod() }
As I say, it works, but I don't like it much. Throwing away the typechecking is not to be done lightly in my opinion. I am only sharing in the hope someone with stronger Swift skills can improve upon it, or correct it.

Function not being called through delegate in Swift

I can't get the app to execute changeCard() after abc() finishes executing. The two functions are in different classes. Here is the code below. Any help is appreciated!
protocol NetworkControllerDelegate {
func changeCard()
}
class NetworkController {
var networkControllerDelegate: NetworkControllerDelegate?
func abc () {
//do something here
networkControllerDelegate?.changeCard()
}
}
class View: UIViewController, NetworkControllerDelegate {
var networkController = NetworkController()
func changeCard() {
//do something here
networkController.networkControllerDelegate = self
}
}
I've read all the similar questions on stackoverflow for the past few hours but still can't figure it out. Thanks!
Try moving the following line into viewDidLoad of your view controller so that the delegate is set up prior to use.
networkController.networkControllerDelegate = self
Also, you might want to think about making the networkControllerDelegate variable in NetworkController weak so as to avoid any retain cycles.