I'm trying to do this but I'm getting some troubles
This is CustomProtocol
protocol CustomProtocol {
}
SubCustomProtocol
protocol SubCustomProtocol: CustomProtocol {
}
SubCustomProtocolImplementation
class SubCustomProtocolImplementation: SubCustomProtocol {
}
This is CustomClass
class CustomClass<P: CustomProtocol> {
var customProtocol: P?
func doSomething() {
}
}
SubCustomClass
class SubCustomClass<P: SubCustomProtocol>: CustomSubClass {
}
And my BaseViewController
class BaseViewController<P: CustomProtocol, T: CustomClass<P>>: UIViewController {
var foo: T!
override func viewDidLoad() {
super.viewDidLoad()
foo?.doSomething()
}
}
My ViewController
class ViewController<P: SubCustomProtocolImplementation, T: SubCustomClass<P>>: BaseViewController<P,T> {
override func viewDidLoad() {
super.viewDidLoad()
}
}
In the line where I call foo?.doSomething() it says that 'T' is not a subtype of 'CustomClass<'P'>' and I don't know what I'm doing wrong
And in the ViewController declaration it says that "BaseViewController requires
that T inherit from CustomClass<'P'>"
Hope you can help me!
If you want to specify your foo var type as CustomClass<P> you should do as following instead.
class ViewController<P: CustomProtocol>: UIViewController {
var foo: CustomClass<P>?
override func viewDidLoad() {
super.viewDidLoad()
foo?.doSomething()
}
}
Related
I have the below code which aims an abstraction -without being have to casting Decodables - for DataModels across the app. I wanted use these DataModels to centrelize them. This is how I far I came right now and I am kind of in dead end.
In this configuration, the code tells me that ProfileResponseDelegate cannot conform to ModelDelegate when ProfileResponseDelegate is a protocol, which makes sense.
protocol ModelDelegate: class {
associatedtype DataType: Decodable
func didReceive(data: DataType)
}
class Model<Type, Delegate: ModelDelegate> where Type == Delegate.DataType {
var data: Type?
weak var delegate: Delegate?
func requestData() { return }
}
protocol ProfileResponseDelegate: ModelDelegate where DataType == ProfileResponse {}
//throws Value of protocol type 'ProfileResponseDelegate' cannot conform to 'ModelDelegate'; only struct/enum/class types can conform to protocols
class ProfileResponseModel: Model<ProfileResponse, ProfileResponseDelegate> {
override func requestData() {
guard let data = data else {
// go to api to get data
return
}
delegate?.didReceive(data: data)
}
}
class Controller: UIViewController, ProfileResponseDelegate {
let model = ProfileResponseModel()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
func didReceive(data: ProfileResponse) {
//tell view code to update regarding data
}
}
When I change ProfileResponseDelegate to be a class -without not being a delegate anymore, but anyway- the code does not allow Controller to inherit from both UIViewController and ProfileResponseDelegate reasoning a class cannot inherit from multiple classes. which again makes sense.
class ProfileResponseDelegate: ModelDelegate {
typealias DataType = ProfileResponse
func didReceive(data: ProfileResponse) {
return
}
}
class Controller: UIViewController, ProfileResponseDelegate {
let model = ProfileResponseModel()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
override func didReceive(data: ProfileResponse) {
//tell view code to update regarding data
}
}
With respect to first configuration, I could not make it work. However for the second one, when Controller just inherits from ProfileResponseDelegate it works just fine.
I have to find a way to make this work -preferably the first configuration- and need your advise. Much appreciated in advance.
UPDATE
So I have removed the associatedType from the ModelDelegate and removed ProfileResponseModel. Right now code looks like this.
protocol ModelDelegate: class {
//associatedtype DataType: Decodable
func didReceive<T: Decodable>(data: T)
}
class Model<Type: Decodable> {
var data: Type?
weak var delegate: ModelDelegate?
func requestData() { return }
}
//protocol ProfileResponseDelegate: ModelDelegate where DataType == ProfileResponse {}
class ProfileResponseModel: Model<ProfileResponse> {
override func requestData() {
guard let data = data else {
// go to api to get data
return
}
delegate?.didReceive(data: data)
}
}
class Controller: UIViewController, ModelDelegate {
let model = ProfileResponseModel()
override func viewDidLoad() {
super.viewDidLoad()
model.delegate = self
model.requestData()
}
func didReceive<T>(data: T) where T : Decodable {
//I want this `data` to come as what it is.
if let response = data as? ProfileResponse {
print(type(of: response))
}
}
}
It works likes this, however my ultimate purpose for doing this to not being have to cast the data to ProfileResponse here -and in other places to other Decodable type-.
In our app, we have a service that helps us decide which Modal UIVIewController should we present next. Every ModalVIewController has common function such as dismiss() but also a specific function it implements. So that's what we tried:
The base protocol that is common to all VC's base functions.
protocol ModalScreenDelegate: AnyObject {
func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen)
}
A base protocol that every UIViewController implements
protocol ModalScreen: UIViewController {
var delegate: ModalScreenDelegate? { get set }
}
Now we create a protocol with specific-implementation of ModalScreenDelegate base protocol like so:
protocol ShareToFacebookDelegate: ModalScreenDelegate {
func someCustomMethod()
}
And assign it to:
class ShareToFacebookViewController: UIViewController, ModalScreen {
weak var delegate: ModalScreenDelegate? // **WORKS**
weak var delegate: ShareToFacebookDelegate? // **DOESN'T WORKS**
}
If I'm trying to use ShareToFacebookDelegate to instead of ModalScreenDelegate the compiler throws an IDE error saying I have to change it back to ModalScreenDelegate.
Why wouldn't it work? It's ShareToFacebookDelegate conforms to ModalScreenDelegate.
Any help would be highly appreciated.
Thank you!
UPDATE Based on Alexandr Kolesnik:
Your method works. But when I try to "fetch" the correct VC within the service under one method like so:
func fetchModal<T: ModalScreen & UIViewController>() -> T? {
return AddInstagramViewController.create() as? T
}
And then have a coordinator that wants to get this vc:
guard let currentModalViewController vc = modalScreenSupplierService.fetchModal() else {
return
}
I'm getting:
Generic parameter 'T' could not be inferred
And I can't really say what T will be, all I know that it's going to conform to UIViewController & ModalScreen. Is it solvable?
If I understood you correctly you can use generic types to manage the problem. Look through the code below. Hope it helps
protocol ModalScreenDelegate: AnyObject {
typealias T = ModalScreenDelegate
func modalScreenWantsToDissmiss(_ modalScreen: T)
}
protocol ShareToFacebookDelegate: ModalScreenDelegate {
func someCustomMethod()
}
protocol ModalScreen: UIViewController {
associatedtype T
var delegate: T? { get set }
}
class ShareToFacebookViewController: UIViewController, ModalScreen {
typealias T = ShareToFacebookDelegate
weak var delegate: T?
override func viewDidLoad() {
super.viewDidLoad()
delegate?.someCustomMethod()
}
}
UPDATE:
class AddInstagramViewController: SuperVC {
typealias T = ShareToFacebookDelegate
private var instaDelegate: ShareToFacebookDelegate?
override var delegate: ModalScreenDelegate? {
set {
instaDelegate = newValue as? ShareToFacebookDelegate
}
get {
return instaDelegate
}
}
static func create() -> AddInstagramViewController {
return AddInstagramViewController()
}
}
class SuperVC: UIViewController, ModalScreen {
typealias T = ModalScreenDelegate
var delegate: T?
}
class Supplier {
func fetchModal<M: ModalScreen>() -> M? { return AddInstagramViewController.create() as? M }
}
class SupplierImpl {
let modalScreenSupplierService: Supplier? = nil
func goto() {
guard
let vc: SuperVC = modalScreenSupplierService?.fetchModal()
else {
return
}
}
}
This solution:
protocol ModalScreenDelegate: AnyObject {
func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen)
}
protocol ModalScreen: UIViewController {
var delegate: (ModalScreenDelegate & ShareToFacebookDelegate)? { get set }
}
protocol ShareToFacebookDelegate: ModalScreenDelegate {
func someCustomMethod()
}
class ShareToFacebookViewController: UIViewController, ModalScreen {
weak var delegate: (ModalScreenDelegate & ShareToFacebookDelegate)?
}
or inheritance:
protocol ModalScreenDelegate: AnyObject {
func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen)
}
protocol ModalScreen: ShareToFacebookDelegate where Self: UIViewController {
var delegate: ModalScreenDelegate? { get set }
}
protocol ShareToFacebookDelegate: ModalScreenDelegate {
func someCustomMethod()
}
class ShareToFacebookViewController: UIViewController, ModalScreen {
func someCustomMethod() {
}
func modalScreenWantsToDissmiss(_ modalScreen: ModalScreen) {
}
weak var delegate: ModalScreenDelegate? // **WORKS**
}
I am struggling with understanding how protocols work. I have 2 files and want to use protocol to pass data... Here's what I am doing:
In ViewController.swift
protocol workingProtocol { func myFunc(strValue: String)}
class ViewController: UIViewController {
var interactor = workingProtocol
#objc func doneBtn() {
interactor.myFunc(strValue: "str")
}
}
In Interactor.swift
class Interactor {
func myFunc(strValue: String) {
print(strValue)
}
}
The data is not printing from Interactor.swift
Unfortunately I can't see how you inject interaction class, also your code has some problem with syntax. Here is how it should look:
protocol WorkingProtocol: AnyObject {
func myFunc(strValue: String)
}
final class ViewController: UIViewController {
var interactor: WorkingProtocol
#objc func doneBtn() {
interactor.myFunc(strValue: "str")
}
}
final class Interactor: WorkingProtocol {
func myFunc(strValue: String) {
print(strValue)
}
}
And how to use:
let interactor: WorkingProtocol = Interactor()
let vc = ViewController(interactor: interactor)
vc.doneBtn()
Protocols defines a blueprint of methods, properties and other requirements that suite a piece of functionality.
This is an example about how it works based on your code
protocol ProtocolName {
func functionName(strValue: String)
}
class ViewController {
var interactor: ProtocolName? = nil
#objc
fileprivate func doneBtn() {
interactor?.functionName(strValue: "Passing data to interactor using protocols")
}
}
class Interactor: ProtocolName {
func functionName(strValue: String) {
print("Showing value\n", strValue)
}
}
let interactor = Interactor()
let viewController = ViewController()
viewController.interactor = interactor
viewController.doneBtn()
Another example:
protocol ProtocolName {
func functionName(strValue: String)
}
class ViewController1 {
let interactor = Interactor1()
/// Init or viewDidLoad() if you're using ViewController classes.
init() {
interactor.delegate = self
}
}
extension ViewController1: ProtocolName {
func functionName(strValue: String) {
print("Printing the value: \(strValue)")
}
}
class Interactor1 {
var delegate: ProtocolName?
func someAction() {
delegate?.functionName(strValue: "Executed action in interactor.")
}
}
let vc = ViewController1()
vc.interactor.someAction()
I saw so many examples with below format
extension Protocolname where Self: UIViewController
What is where Self in protocol extension. I couldn't find the documentation on this.
That syntax is: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID521
Consider:
protocol Meh {
func doSomething()
}
// Extend protocol Meh, where `Self` is of type `UIViewController`
// func blah() will only exist for classes that inherit `UIViewController`.
// In fact, this entire extension only exists for `UIViewController` subclasses.
extension Meh where Self: UIViewController {
func blah() {
print("Blah")
}
func foo() {
print("Foo")
}
}
class Foo : UIViewController, Meh { //This compiles and since Foo is a `UIViewController` subclass, it has access to all of `Meh` extension functions and `Meh` itself. IE: `doSomething, blah, foo`.
func doSomething() {
print("Do Something")
}
}
class Obj : NSObject, Meh { //While this compiles, it won't have access to any of `Meh` extension functions. It only has access to `Meh.doSomething()`.
func doSomething() {
print("Do Something")
}
}
The below will give a compiler error because Obj doesn't have access to Meh extension functions.
let i = Obj()
i.blah()
But the below will work.
let j = Foo()
j.blah()
In other words, Meh.blah() is only available to classes that are of type UIViewController.
Here is an example which explains that what is the use of where self: UIViewController
protocol SBIdentifiable {
static var sbIdentifier: String { get }
}
extension SBIdentifiable where Self: UIViewController {
static var sbIdentifier: String {
return String(describing: self)
}
}
extension UIVieWcontroller: SBIdentifiable { }
class ViewController: UIViewController {
func loadView() {
/*Below line we are using the sbIdentifier which will return the
ViewController class name.
and same name we would mentioned inside ViewController
storyboard ID. So that we do not need to write the identifier everytime.
So here where Self: UIViewController means it will only conform the protocol of type UIViewController*/
let viewController = self.instantiateViewController(withIdentifier:
self.sbIdentifier) as? SomeBiewController
}
}
You can find the same example here: WWDC2015-408, (Highly recommend to watch it,it illustrates the reason)
And also, another similar example is Extensions with a Generic Where Clause
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
The where clause add a requirement to the extension, so that the extension adds the isTop(_:) method only when the items in the stack are equatable.
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
i have this error :
Type 'CategoryTableViewController' does not conform to protocol 'XMLParserDelegateCategory'
in this code:
class CategoryTableViewController: UITableViewController, XMLParserDelegateCategory {
var parser = CategoryParser(url: kURL)
var parsedItems: [CategorySchemes] = []
override func viewDidLoad() {
super.viewDidLoad()
title = "Navigation Mode"
parser.delegate = self
parser.parse {
self.tableView.reloadData()
}
}
And my protocol is:
protocol XMLParserDelegateCodelist {
func XMLParserError(parser: CodeListParser, error: String) }
class CodeListParser: NSObject, NSXMLParserDelegate {
let url: NSURL
var delegate: XMLParserDelegateCodelist?
any suggestions?
Thanks.
Implement func XMLParserError(parser: CodeListParser, error: String) in your view controller.