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
}
}
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-.
I have this protocols:
One to instantiate a ViewController from Storyboard:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
// this pulls out "MyApp.MyViewController"
let fullName = NSStringFromClass(self)
// this splits by the dot and uses everything after, giving "MyViewController"
let className = fullName.components(separatedBy: ".")[1]
// load our storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// instantiate a view controller with that identifier, and force cast as the type that was requested
return storyboard.instantiateViewController(withIdentifier: className) as! Self
}
}
One to inject Dependencies in to Viewcontrollers:
protocol DependencyInjection where Self: UIViewController {
associatedtype myType: DependencyVC
func injectDependencys(dependency: myType)
}
Now I want to add another one, so I can create the ViewController from the Dependency itself:
protocol DependencyVC {
associatedtype myType: DependencyInjectionVC & Storyboarded
func createVC() -> myType
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
But I get this error for self:
Cannot invoke 'injectDependencys' with an argument list of type
'(dependency: Self)'
This is a DependencyClass I have:
class TopFlopDependency: DependencyVC {
typealias myType = TopFlopVC
var topFlopState: TopFlopState
lazy var topFlopConfig: TopFlopConfig = {
let SIBM = StatIntervalBaseModel(stat: "ppc", interval: "24h", base: "usd")
return TopFlopConfig(group: Groups.large, base: "usd", valueOne: SIBM)
}()
init(state: TopFlopState) {
self.topFlopState = state
}
func createVC() -> TopFlopVC {
let topflopVC = TopFlopVC.instantiate()
topflopVC.injectDependencys(dependency: self)
let viewController: TopFlopVC = makeVC()
return topflopVC
}
}
I get this error when using makeVC:
'TopFlopDependency' requires the types 'TopFlopDependency.myType' and
'TopFlopDependency.myType' (aka 'TopFlopVC') be equivalent to use
'makeVC'
other Solution:
protocol DependencyVC {
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
When trying to use:
let viewController: TopFlopVC = makeVC()
I get the error that T could not be inferred.
Why can I not do this? Do you have a solution how I would get it to work?
Thank you!
You need to add another constraint. Your DependencyInjection protocol requires a very specific type of DependencyVC (myType). But your DependencyVC extension works with any DependencyVC. So you need to constrain T’s myType to be the same type with a where clause: func createVC<T: Storyboarded & DependencyInjection>() -> T where T.myType == Self
So a complete example would look like this:
protocol Storyboarded {
static func instantiate() -> Self
}
extension Storyboarded where Self: UIViewController {
static func instantiate() -> Self {
...
}
}
protocol DependencyVC {
}
protocol DependencyInjection where Self: UIViewController {
associatedtype myType: DependencyVC
func injectDependencys(dependency: myType)
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>(type _: T.Type? = nil) -> T where T.myType == Self {
let viewController = T.instantiate()
viewController.injectDependencys(dependency: self)
return viewController
}
}
struct MyDependency: DependencyVC {}
class MyVC: UIViewController, Storyboarded, DependencyInjection {
func injectDependencys(dependency: MyDependency) {
print(dependency)
}
}
When you call viewController.injectDependencys(dependency: self), self is known to be of some subtype of DependencyVC. However, DependencyInjection's associatedtype myType: DependencyVC just says that a type conforming to DependencyInjection will use some type for myType (that conforms to DependencyVC). So there's no guarantee that its actual type will be a subtype of myType.
associatedtypes don't quite work the same way as generic type parameters in that associatedtypes are given when "defining" a type, while generic type parameters are given when "using" a type.
It all boils down to the fact that you probably don't want to have an associatedtype myType, instead taking a DependencyVC directly.
Update
In light of the additional information you've provided, I believe this would be the best solution:
protocol DependencyInjection where Self: UIViewController {
func injectDependency(_ dependency: DependencyVC)
}
protocol DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T
}
extension DependencyVC {
func makeVC<T: Storyboarded & DependencyInjection>() -> T {
let viewController = T.instantiate()
viewController.injectDependency(self)
return viewController
}
}
As you may notice, I took the liberty of renaming injectDependencys(dependency: DependencyVC) to injectDependency(_ dependency: DependencyVC), because you're only injecting one dependency and the dependency: label doesn't really add anything at the call site.
Anyway, this allows you to create instances of view controllers using your dependency. Say you have the dependency stored in a variable named dependency, then you can create a view controller from it by going let topFlopVC: TopFlopVC = dependency.makeVC()
Is it possible to add the same methods to different classes?
Example:
class FilterableTable: UITableViewController { ... }
class FilterableCollection: UICollectionViewController { ... }
extension FilterableTable, FilterableCollection { // I know this line is wrong
func filterItems(){ print('filtered!') }
}
How can I add the same Foo method to a UICollectionViewController?
Protocols allow to declare only needed methods signatures, but I need exactly the same method (with body), to avoid copy-paste...
You can use the Protocol Extensions to do what you need. Extensions are new and allow for a default implementation of the protocol methods. I modified your code just a bit so it would compile.
class FilterableTable: FilterType {
init() {}
}
class FilterableCollection: FilterType {
init() {}
}
protocol FilterType {
func filterItems()
}
extension FilterType { // I know this line is wrong
func filterItems(){ print("filtered!") }
}
let a = FilterableTable()
a.filterItems()
let b = FilterableCollection()
b.filterItems()
Check out the section on Protocol Extensions. Swift Programming Guide
Actual answer: Use the Delegates, Luke!
class FilterableTable: UITableViewController {
var filterDelegate: FilterDelegate!
func viewDidLoad(){
filterDelegate = Filter()
}
}
class FilterableCollection: UICollectionViewController {
var filterDelegate: FilterDelegate!
func viewDidLoad(){
filterDelegate = Filter()
}
}
protocol FilterDelegate {
func filterItems()
}
class Filter: FilterDelegate {
func filterItems() {
print("Hooray!")
}
}
I'm wondering if it's possible to achieve such a thing.
I have a Playground like this:
protocol Foo {
func testPrint()
}
extension Foo {
func testPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
// Calling self or super go call default implementation
self.testPrint()
print("Call from struct")
}
}
let sth = Bar()
sth.testPrint()
I can provide a default implementation in extension but what if Bar needs everything that is in default implementation plus additional things?
It's somehow similar to calling super. methods in classes to fulfill requirement of implementing every property etc. but I see no possibility to achieve the same with structs.
I don't know if you are still looking for an answer to this, but the way to do it is to remove the function from the protocol definition, cast your object to Foo and then call the method on it:
protocol Foo {
// func testPrint() <- comment this out or remove it
}
extension Foo {
func testPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
print("Call from struct")
(self as Foo).testPrint() // <- cast to Foo and you'll get the default
// function defined in the extension
}
}
Bar().testPrint()
// Output: "Call from struct"
// "Protocol extension call"
For some reason it only works if the function isn't declared as part of the protocol, but is defined in an extension to the protocol. Go figure. But it does work.
Well, you could create a nested type conforming to the protocol, instantiate it, and call the method on that one (it does not matter that you cannot access your type's data as the implementation inside the protocol extension cannot reference it anyway). But it's not a solution I'd call elegant.
struct Bar: Foo {
func testPrint() {
// Calling default implementation
struct Dummy : Foo {}
let dummy = Dummy()
dummy.testPrint()
print("Call from struct")
}
}
what do you think about such way of fixing this ?
protocol Foo {
func testPrint()
}
extension Foo {
func testPrint() {
defaultTestPrint()
}
func defaultTestPrint() {
print("Protocol extension call")
}
}
struct Bar: Foo {
func testPrint() {
// Calling self or super go call default implementation
defaultTestPrint()
print("Call from struct")
}
}
let sth = Bar()
sth.testPrint()
Thanks for the post! If you put the function definition in the protocol then when the object is casted as the protocol it only sees the object's version of the function and since you are calling it inside itself you get the new address of Apple ...
I did try a version like this:
import UIKit
protocol MyProc
{
}
protocol MyFuncProc
{
func myFunc()
}
extension MyProc
{
func myFunc()
{
print("Extension Version")
}
}
struct MyStruct: MyProc, MyFuncProc
{
func myFunc()
{
print("Structure Version")
(self as MyProc).myFunc()
}
}
(MyStruct() as MyFuncProc).myFunc()
This gives an output of:
Structure Version
Extension Version
In case your protocol has associatedType or Self requirements, then the cast will not work. To work around this, create a "shadow" default implementation that both the regular default implementation and the conforming type can call.
protocol Foo {
associatedType Bar
}
extension Foo {
func testPrint() {
defaultTestPrint()
}
}
fileprivate extension Foo { // keep this as private as possible
func defaultTestPrint() {
// default implementation
}
}
struct Bar: Foo {
func testPrint() {
// specialized implementation
defaultTestPrint()
}
}
I have come up with a solution for this.
Issue
When you have a default implementation in an extension, when you implement the protocol to another class/struct, you lose this default implementation if you implement the method. This is by design, this is how protocols work
Solution
Create a Default Implementation of your protocol and make it a property of your protocol.
Then when you implement this protocol in a class, provide your default implementation with a getter
Call default implementation when you need to.
Example
protocol Foo {
var defaultImplementation: DefaultImpl? { get }
func testPrint()
}
extension Foo {
// Add default implementation
var defaultImplementation: DefaultImpl? {
get {
return nil
}
}
}
struct DefaultImpl: Foo {
func testPrint() {
print("Foo")
}
}
extension Foo {
func testPrint() {
defaultImplementation?.testPrint()
}
}
struct Bar: Foo {
var defaultImplementation: DefaultImpl? {
get { return DefaultImpl() }
}
func testPrint() {
if someCondition {
defaultImplementation?.testPrint() // Prints "Foo"
}
}
}
struct Baz: Foo {
func testPrint() {
print("Baz")
}
}
let bar = Bar()
bar.testPrint() // prints "Foo"
let baz = Baz()
baz.testPrint() // prints "Baz"
Drawbacks
You lose the required implementation error in the struct/class where you implement this protocol.
Is there a standard way to make a "pure virtual function" in Swift, ie. one that must be overridden by every subclass, and which, if it is not, causes a compile time error?
You have two options:
1. Use a Protocol
Define the superclass as a Protocol instead of a Class
Pro: Compile time check for if each "subclass" (not an actual subclass) implements the required method(s)
Con: The "superclass" (protocol) cannot implement methods or properties
2. Assert in the super version of the method
Example:
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
Pro: Can implement methods and properties in superclass
Con: No compile time check
The following allows to inherit from a class and also to have the protocol's compile time check :)
protocol ViewControllerProtocol {
func setupViews()
func setupConstraints()
}
typealias ViewController = ViewControllerClass & ViewControllerProtocol
class ViewControllerClass : UIViewController {
override func viewDidLoad() {
self.setup()
}
func setup() {
guard let controller = self as? ViewController else {
return
}
controller.setupViews()
controller.setupConstraints()
}
//.... and implement methods related to UIViewController at will
}
class SubClass : ViewController {
//-- in case these aren't here... an error will be presented
func setupViews() { ... }
func setupConstraints() { ... }
}
There isn't any support for abstract class/ virtual functions, but you could probably use a protocol for most cases:
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Another workaround, if you don't have too many "virtual" methods, is to have the subclass pass the "implementations" into the base class constructor as function objects:
class MyVirtual {
// 'Implementation' provided by subclass
let fooImpl: (() -> String)
// Delegates to 'implementation' provided by subclass
func foo() -> String {
return fooImpl()
}
init(fooImpl: (() -> String)) {
self.fooImpl = fooImpl
}
}
class MyImpl: MyVirtual {
// 'Implementation' for super.foo()
func myFoo() -> String {
return "I am foo"
}
init() {
// pass the 'implementation' to the superclass
super.init(myFoo)
}
}
You can use protocol vs assertion as suggested in answer here by drewag.
However, example for the protocol is missing. I am covering here,
Protocol
protocol SomeProtocol {
func someMethod()
}
class SomeClass: SomeProtocol {
func someMethod() {}
}
Now every subclasses are required to implement the protocol which is checked in compile time. If SomeClass doesn't implement someMethod, you'll get this compile time error:
error: type 'SomeClass' does not conform to protocol 'SomeProtocol'
Note: this only works for the topmost class that implements the protocol. Any subclasses can blithely ignore the protocol requirements. – as commented by memmons
Assertion
class SuperClass {
func someFunc() {
fatalError("Must Override")
}
}
class Subclass : SuperClass {
override func someFunc() {
}
}
However, assertion will work only in runtime.
This is what I usually do, to causes the compile-time error :
class SuperClass {}
protocol SuperClassProtocol {
func someFunc()
}
typealias SuperClassType = SuperClass & SuperClassProtocol
class Subclass: SuperClassType {
func someFunc() {
// ...
}
}
You can achieve it by passing function into initializer.
For example
open class SuperClass {
private let abstractFunction: () -> Void
public init(abstractFunction: #escaping () -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction()
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
print("my implementation")
}
)
}
}
You can extend it by passing self as the parameter:
open class SuperClass {
private let abstractFunction: (SuperClass) -> Void
public init(abstractFunction: #escaping (SuperClass) -> Void) {
self.abstractFunction = abstractFunction
}
public func foo() {
// ...
abstractFunction(self)
}
}
public class SubClass: SuperClass {
public init() {
super.init(
abstractFunction: {
(_self: SuperClass) in
let _self: SubClass = _self as! SubClass
print("my implementation")
}
)
}
}
Pro:
Compile time check for if each subclassimplements the required method(s)
Can implement methods and properties in superclass
Note that you can't pass self to the function so you won't get memory leak.
Con:
It's not the prettiest code
You can't use it for the classes with required init
Being new to iOS development, I'm not entirely sure when this was implemented, but one way to get the best of both worlds is to implement an extension for a protocol:
protocol ThingsToDo {
func doThingOne()
}
extension ThingsToDo {
func doThingTwo() { /* Define code here */}
}
class Person: ThingsToDo {
func doThingOne() {
// Already defined in extension
doThingTwo()
// Rest of code
}
}
The extension is what allows you to have the default value for a function while the function in the regular protocol still provides a compile time error if not defined