weak property conforming to protocol with generic constraint - swift

I wrote simplified version of similar implementation I'm having problem with. Anyone knows why is that and eventually how to workaround?
NOTE: the code is just example to keep it as simple as possible
protocol Alertable {
associatedtype Alert
func show(alertOfType alertType: Alert)
}
protocol ViewControllerDelegate: class, Alertable {
}
final class MyViewController: UIViewController {
// MARK: - Types
enum AlertType {
case alert
case warning
}
}
extension MyViewController: ViewControllerDelegate {
typealias Alert = AlertType // ! here i specify the associated type !
func show(alertOfType alertType: Alert) {
// code..
}
}
So far so good. But, here I get errors:
final class ViewModel {
// ERROR: Protocol 'ViewControllerDelegate' can only be used as a generic constraint because it has Self or associated type requirements.
weak var viewController: ViewControllerDelegate?
init(viewController: ViewControllerDelegate?) {
self.viewController = viewController
}
private func someFunction() {
// ERROR: Member 'show' cannot be used on value of protocol type 'NewsFeedViewControllerInput'; use a generic constraint instead.
viewController?.show(alertOfType: .warning)
// code..
}
}
Thank you

You had a bit of a misunderstanding here. When you define:
protocol ViewControllerDelegate: class, Alertable {}
extension MyViewController: ViewControllerDelegate {
typealias Alert = AlertType // ! here i specify the associated type !
func show(alertOfType alertType: Alert) {
// code..
}
}
The typealias is defined in MyViewController but not ViewControllerDelegate. It's not clear why you need ViewControllerDelegate in this question but maybe there's something we don't see in the real app.
In ViewModel, change from ViewControllerDelegate to MyViewController:
final class ViewModel {
weak var viewController: MyViewController?
// ...
}
One more thing, though unrelated to the error: you use many final classes. Should they be structs instead?

Related

Using protocol's associated type in generic functions

I'm trying to write a simple MVP pattern to follow in my app, so I've written two porotocols to define View Controller and Presenters:
protocol PresenterType: class {
associatedtype ViewController: ViewControllerType
var viewController: ViewController? { get set }
func bind(viewController: ViewController?)
}
protocol ViewControllerType: class {
associatedtype Presenter: PresenterType
var presenter: Presenter { get }
init(presenter: Presenter)
}
After having those defined I started writing some RootViewController and RootViewPresenter. The latter looks like:
protocol RootViewControllerType: ViewControllerType {
}
final class RootPresenter<VC: RootViewControllerType>: PresenterType {
weak var viewController: VC?
func bind(viewController: VC?) {
self.viewController = viewController
}
}
Up to this point everything complies and is fine, but when I start implementing View Controller like this:
protocol RootPresenterType: PresenterType {
}
final class RootViewController<P: RootPresenterType>: UIViewController, ViewControllerType {
let presenter: P
init(presenter: Presenter) {
self.presenter = presenter
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
presenter.bind(viewController: self)
}
}
Immediately I get the following error message:
Cannot convert value of type 'RootViewController' to expected argument type '_?'
I know that protocols with associated types can introduce some limitations, but this example is pretty straightforward and I can't make it work. Is it possible to achieve something that I want, or do I have to look for some other, less Swifty pattern?
I don't think what you're trying to achieve is possible due to the circular dependency between the respective associated types of the PresenterType and ViewControllerType protocols.
Consider for a moment if the suspect code above did compile ... how would you go about instantiating either the RootPresenter or RootViewController classes? Because both depend on one another, you'll end up with errors like the following:
As you can see, the compiler can't fully resolve the generic parameters due to the associated types.
I think your best bet is to remove the associated type from one or both of the protocols. For example, removing the associated type from the PresenterType protocol and updating the RootPresenter class breaks the circular dependency and allows your code to compile normally.
protocol PresenterType: class {
var viewController: UIViewController? { get set }
func bind(viewController: UIViewController?)
}
final class RootPresenter: PresenterType {
weak var viewController: UIViewController?
func bind(viewController: UIViewController?) {
self.viewController = viewController
}
}

how do i call a protocol in one class from another in swift?

I have my viewcontroller that implements one Protocol,
import UIKit
class FirstScreenViewController: UIViewController, mainViewProtocol {
var presenter: mainPresenterProtocol?
//Protocol Functions
static func showSmallHeadline(textToShow: String) {
<#code#>
}
func showHeadline(textToShow: String) {
<#code#>
}
}
I have my presenter that implement second Protocol
import Foundation
class MainPresenter: mainPresenterProtocol {
var screenViewController: mainViewProtocol?
//confirms protocol
static func presenterProtocolFuncOne() {
<#code#>
}
func presenterProtocolFuncTwo(numOne: Int, numTwo: Int, sucssesMessage: String, failMessage: String) -> String {
<#code#>
}
func presenterProtocolFucThree() -> Bool {
<#code#>
}
}
how do I call the functions in my presenter (that implements them through the protocol) from my viewcontroller,
and how do I call the functions in my viewcontroller (that implements them through the protocol) from my presenter ?
Thank you !
The key thing here - strong relationship between controller and presenter. You should avoid that by adding weak to presenter property in controller.
protocol MainViewProtocol {
func controllerProtocolFunc()
}
protocol MainPresenterProtocol: class {
func presenterProtocolFunc()
}
class FirstScreenViewController: UIViewController, MainViewProtocol {
weak var presenter: MainPresenterProtocol?
func controllerProtocolFunc() { }
}
class MainPresenter: MainPresenterProtocol {
var screenViewController: MainViewProtocol?
func presenterProtocolFunc() { }
}
Next step, when you need to call presenter(controller) func from controller(presenter), simply call it with optional chaining:
presenter?.presenterProtocolFunc()
// or
screenViewController?.controllerProtocolFunc()
P.S. Also, note from docs:
Because protocols are types, begin their names with a capital letter
(such as FullyNamed and RandomNumberGenerator) to match the names of
other types in Swift (such as Int, String, and Double).
Add properties to each class referencing the other object by the type of the protocol.
class FirstScreenViewController: UIViewController, mainViewProtocol {
var presenter: mainPresenterProtocol?
// rest of the code
}
class MainPresenter: mainPresenterProtocol {
var screenViewController: mainViewProtocol?
// rest of the code
}
Assign the properties after constructing both objects. The ? after the protocol type makes them optional, allowing you delay the assignment to the point in time when both objects exist. Alternatively, you can swap out the ? for a ! if you are certain the properties will be assigned non-nil values, so you can save a lot of nil-checking and dereferencing.
let viewController = FirstScreenViewController()
let mainPresenter = MainPresenter()
viewController.presenter = mainPresenter
presenter.screenViewController = viewController

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.

Altering (refining) delegate type in swift

I have a (swift) class which has a weak pointer to a delegate like this:
import UIKit
#objc public protocol DRSlidingPanelViewControllerDelegate : class {
optional func didSlidePanel(panelHidden : Bool , sender : DRSlidingPanelViewController) -> Void
}
public class DRSlidingPanelViewController: UIViewController {
public weak var delegate : DRSlidingPanelViewControllerDelegate?
///other stuff...
}
Now i make a subclass with another protocol which extends the first, and i want to alter the inherited 'delegate' property
#objc public protocol DRTableViewControllerDelegate : DRSlidingPanelViewControllerDelegate {
optional func someFunction(sender : DRTableViewController) -> Void
}
public class DRTableViewController: DRSlidingPanelViewController {
// public weak var delegate : DRTableViewControllerDelegate?
}
^ this (re)declaration of delegate in the subclass gives me 3 errors when I uncomment it.
Property 'delegate' with type 'DRTableViewControllerDelegate?' (aka 'Optional') cannot override a property with type 'DRSlidingPanelViewControllerDelegate?' (aka 'Optional')
Getter for 'delegate' with Objective-C selector 'delegate' conflicts with getter for 'delegate' from superclass 'DRSlidingPanelViewController' with the same Objective-C selector
Setter for 'delegate' with Objective-C selector 'setDelegate:' conflicts with setter for 'delegate' from superclass 'DRSlidingPanelViewController' with the same Objective-C selector
Now i understand the nature of these errors, and that they are different facets of the one error (attempting to change the 'type' on the delegate pointer.) Can anybody give me a clue how to do this? It obviously can be done, look at how UITableView alters the delegate pointer which it inherits from UIScrollView. In objC I would get a warning which could be silenced with an #dynamic.
Thanks and best regards
edit / addition
Thanks Matt, I do see this previous question, but unfortunately it is closed and I would personally not accept that answer as the definitive answer because it is a compromise.
If I right click on UITableView in xCode and 'jump to definition' I see this
#available(iOS 2.0, *)
public class UITableView : UIScrollView, NSCoding {
public init(frame: CGRect, style: UITableViewStyle) // must specify style at creation. -initWithFrame: calls this with UITableViewStylePlain
public init?(coder aDecoder: NSCoder)
public var style: UITableViewStyle { get }
weak public var dataSource: UITableViewDataSource?
**weak public var delegate: UITableViewDelegate?**
//plenty other stuff..
}
So I respectfully submit that there definitely is a way to do this.
I would say that as things stand you can't do it. This is disappointing to say the least. You'll just have to call the delegate variable in the subclass something else.
So, this is legal, but of course it totally fails to meet your requirements:
#objc protocol P1 {
}
#objc protocol P2 : P1 {
}
public class VC1: UIViewController {
weak var delegate : P1?
}
public class VC2: VC1 {
weak var delegate2 : P2?
}
If you really hate the multiplication of storage you can make the delegate2 a computed variable that accesses the inherited delegate:
#objc protocol P1 {
}
#objc protocol P2 : P1 {
}
public class VC1: UIViewController {
weak var delegate : P1?
}
public class VC2: VC1 {
weak var delegate2 : P2? {
set {
super.delegate = newValue
}
get {
return super.delegate as? P2
}
}
}

NSViewController delegate?

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.