How to call a protocol's default function declared in a protocol extension? - ios

I'm trying to call a protocol's default function that was declared in an extension:
protocol Tester {
func printTest()
}
extension Tester {
func printTest() {
print("XXXXTestXXXX")
}
}
class TestController: UIViewController, Tester {
let testing = Tester()// error here
override func viewDidLoad() {
super.viewDidLoad()
testing.printTest()
}
}
The error ''Tester' cannot be constructed because it has no accessible initializers' keeps appearing when I try to create an instance of the protocol. Whats the best way to use default functions in protocols?

You have to call the implementer, in your case it's TestController so :
self.printTest() will work

protocol Proto {
// func testPrint() <- comment this out or remove it
}
extension Proto {
func testPrint() {
print("This extension called")
}
}
struct Bar: Proto {
func testPrint() {
print("Call from Structure")
(self as Foo).testPrint()
}
}
Bar().testPrint()
// Output: 'Call from Structure',
// 'This extension call'

Protocols cannot be instantiated - ever - lets think of them Contracts
Classes CAN supposed to confrom to 1..n protocols.
The fact that your protocol provides a default implementation, just enables a class that conforms to it to inherit this default functionality if it doesnt need to provide a custom implementation.
a very cheap way in your case would be:
let testing = self
since your TestController class already conforms to Tester.
(Note I create a retain cycle)
===
another way would be to not use testing but self.printTest()
(This might be what you want)
Id reread the apple swift book and check out protocols (what they are and how they work)

Related

Cannot satisfy protocols (with associatedtype) comformance

I'm working with CleanSWift in my new project and I'm facing that it's too wordy. To automate some of the basic stuff, I wrote following tools (simplified):
// MARK: - Presenter
protocol Presenter {
associatedtype DisplayLogic
var viewController: DisplayLogic? { get set }
}
protocol PresentationLogic {
func show(_ error: Error)
}
extension PresentationLogic where Self: Presenter, Self.DisplayLogic: DefaultDisplayLogic {
func show(_ error: Error) {
}
}
// MARK: - Display logic
protocol DefaultDisplayLogic: class {
// func present(_ error: Error)
}
protocol TableViewDisplayLogic: DefaultDisplayLogic {
// func reloadTableView(with sections: [Section])
}
When I try to implement the code above, generics seems to be broken. I'm getting an error saying "Type 'MyPresenter' does not conform to protocol 'PresentationLogic'." However, everything seems fine to me.
// MARK: - Controller
protocol MyDisplayLogic: DefaultDisplayLogic {
}
class MyViewController: UIViewController, MyDisplayLogic {
}
// MARK: - Interactor
protocol MyBusinessLogic {
}
class MyInteractor: MyBusinessLogic {
var presenter: MyPresentationLogic?
func test() {
presenter?.show(TestError.unknown)
}
}
// MARK: - Presenter
protocol MyPresentationLogic: PresentationLogic {
}
class MyPresenter: Presenter, MyPresentationLogic {
weak var viewController: MyDisplayLogic? // ** Here I get the error. **
}
Any ideas? Thank you.
Currently, MyPresenter doesn't fulfill the requirements of the where clause of the PresentationLogic extension, so it can't use the default implementation of show(_:). Specifically, it doesn't pass the test for Self.DisplayLogic: DefaultDisplayLogic. Therefore, it doesn't conform to PresentationLogic, and so it also doesn't conform to MyPresentationLogic, which inherits from PresentationLogic.
But why not? I think it's caused by how Swift works: protocols can't conform to themselves. In MyPresenter, Self.DisplayLogic is MyDisplayLogic. Though it is a descendent protocol of DefaultDisplayLogic, it still seems to function as "a protocol trying to conform to itself", so it doesn't work.
To demonstrate this, you can replace weak var viewController: MyDisplayLogic? with weak var viewController: MyViewController, and the error will go away, since it's a concrete type that conforms to DefaultDisplayLogic. Also, if you change Self.DisplayLogic: DefaultDisplayLogic in the where clause to Self.DisplayLogic == MyDisplayLogic, the error will go away because you are requiring a specific type rather than a conformance.
In your case, a possible solution is to make MyPresenter a generic class. For example:
class MyPresenter<ConcreteDisplayLogic: DefaultDisplayLogic>: Presenter, MyPresentationLogic {
weak var viewController: ConcreteDisplayLogic?
}
That will allow you to use the same where clause constraints for your default implementation of show(_:), while providing a type-safe, generic implementation of MyPresenter.
There is a limitation to this approach: you can't change the type of the value of viewController for a single instance of MyPresenter.

Swift protocol and extension, I need to call overridden method or default extension method as per requirement

I have a protocol Vehicle and its extension like below:
protocol Vehicle {
func Drive()
}
extension Vehicle {
func Stop() {
print("iiiich...")
}
}
And I also have declaration like below for Stop Method
struct Car: Vehicle {
func Drive() {
print("Can Drive")
}
func Stop() {
print("yo stop")
}
}
let myCar = Car()
myCar.Drive()
myCar.Stop()
But its override the Stop Method
// Output
// Can Drive
// yo stop
And as per my requirement I need default method sometime and some time overridden method definition
Hey I got the answers that is to conform the protocol by the object call your default method rather than overriddedn, so we can call both defination as required
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
// Output
// Can Drive
// iiiich..
When we create a variable without type then this is static dispatch when a object conform a protocol only.
If you need the method declared in the protocol extension, just make the compiler think that the car is of type Vehicle:
let myCar = Car()
(myCar as Vehicle).Stop()
As already mentioned in the answers, the generic solution is to make sure that the instance that calls Stop() method is of type Vehicle (not Car). Nevertheless I would mention what's the logic behind it.
Personally, I think that there is a possibility to face this issue when it comes to work with the POP paradigm. Protocol extensions is a handy way the apply Polymorphism in our code, however it does leads to this "weird" behavior!
Static Dispatch:
Firstly, keep in mind that it is not a bug. In case of:
let honda: Vehicle = Car()
honda.Drive()
honda.Stop()
there is a manual cast to the honda as Vehicle, at this point the compiler will use static dispatch, which means that it would be recognizable which method should be called (Vehicle().Stop or Car().Stop) during the compile time. It selects the default implementation for Vehicle which is implemented in the extension, without the need of checking what is the concrete type.
Dynamic Dispatch:
In case of:
let myCar = Car()
myCar.Drive()
myCar.Stop()
nothing special goes here, it works exactly as expected. That's exactly the the meaning of dynamic dispatch, which leads to apply polymorphic operations during the run time.
To make it more clear, consider that you have another type that conforms to Vehicle protocol:
struct Bus: Vehicle {
func Drive() {
print("Bus Drive")
}
func Stop() {
print("Bus stop")
}
}
let myBus = Bus()
myCar.Drive()
myCar.Stop()
Obviously, the print("Bus stop") is the one which will be called, and actually that's the expected! The compiler is "smart" enough to recognize which method to be selected based on what is the concrete type (Bus().Stop).
Furthermore:
For better understanding of what's going on here, reviewing Understanding Swift Performance Apple session might be helpful.
You need a protocol with a default implementation that allows a struct param, that can do custom behaviors:
import UIKit
struct Car{
//Any properties
func drive(){
print("Yo Drive")
}
func stop(){
print("Yo Stop")
}
}
protocol Vehicle {
func drive(vehicle : Car?)
func stop(vehicle : Car?)
}
extension Vehicle where Self: UIViewController {
func drive(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.drive()
}else{
print("drive default behavior")
}
}
func stop(vehicle : Car? = nil) {
if (vehicle != nil){
vehicle?.stop()
}else{
print("stop default behavior")
}
}
}
class ViewController : UIViewController, Vehicle {
func driving() {
drive() //will print drive default behavior
stop() //will print stop default behavior
let car = Car()
drive(vehicle: car) //will print yo drive!
stop(vehicle: car) //will print yo Stop!
}
override func viewDidLoad() {
driving()
}
}

How to override instance method from protocol extension in Swift? [duplicate]

This question already has an answer here:
Implement protocol through extension [duplicate]
(1 answer)
Closed 6 years ago.
I'm trying to override an instance method from a protocol extension, and I'm having some trouble.
For context, I'm making an iOS app with a lot of different UICollectionViews. These views get data from different databases (requiring different callback funcs) and have very different layouts. Because any combination of (database, layout) is possible, it's difficult to make a nice OOP class hierarchy without massive code duplication.
I had the idea to put the layout functions (mostly those defined in the UICollectionViewDelegateFlowLayout protocol) into protocol extensions, so I can decorate a given UICollectionView subclass with a protocol that's extended to implement all relevant layout functions, but I'm having a hard time of it. The essence of the problem is contained in the code below.
class Base {
func speak(){
print("Base")
}
}
class SubA: Base, ProtocolA {}
class SubB: Base, MyProtocolB {}
protocol MyProtocolA{
func speak()
}
protocol MyProtocolB{
func speak()
}
extension MyProtocolA{
func speak(){
print("A")
}
}
extension MyProtocolA{
func speak(){
print("B")
}
}
let suba = SubA()
suba.speak() // prints "Base", I want it to print "A"
let subb = SubB()
subb.speak() // prints "Base", I want it to print "B"
Thoughts?
The default implementations in the protocols are only called if the class that conforms to these protocols do not implement that method itself. The classes' methods override the default implementations of the protocols, not the other way around.
Typically, you'd do something like:
protocol MyProtocolA {
func speak()
}
protocol MyProtocolB {
func speak()
}
extension MyProtocolA {
func speak() {
print("A")
}
}
extension MyProtocolB {
func speak() {
print("B")
}
}
class SubA: MyProtocolA {}
class SubB: MyProtocolB {}
let suba = SubA()
suba.speak() // prints "A"
let subb = SubB()
subb.speak() // prints "B"
But if you do
class SubC: MyProtocolA {
func speak (){
print("C")
}
}
let subc = SubC()
subc.speak() // prints "C"
Frankly, as you look at this, the use of Base is entirely redundant in this example, so I've removed it. Clearly, if you need to subclass from Base for other reasons, feel free. But the key point is that protocol default implementations don't override the classes' implementation, but rather the other way around.

Is use of generics valid in XCTestCase subclasses?

I have a XCTestCase subclass that looks something like this. I have removed setup() and tearDown methods for brevity:
class ViewControllerTests <T : UIViewController>: XCTestCase {
var viewController : T!
final func loadControllerWithNibName(string:String) {
viewController = T(nibName: string, bundle: NSBundle(forClass: ViewControllerTests.self))
if #available(iOS 9.0, *) {
viewController.loadViewIfNeeded()
} else {
viewController.view.alpha = 1
}
}
}
And its subclass that looks something like this :
class WelcomeViewControllerTests : ViewControllerTests<WelcomeViewController> {
override func setUp() {
super.setUp()
self.loadControllerWithNibName("welcomeViewController")
// Put setup code here. This method is called before the invocation of each test method in the class.
}
func testName() {
let value = self.viewController.firstNameTextField.text
if value == "" {
XCTFail()
}
}
}
In theory, this should work as expected -- the compiler doesn't complain about anything. But it's just that when I run the test cases, the setup() method doesn't even get called. But, it says the tests have passed when clearly testName() method should fail.
Is the use of generics a problem? I can easily think of many non-generic approaches, but I would very much want to write my test cases like this. Is the XCTest's interoperability between Objective-C and Swift the issue here?
XCTestCase uses the Objective-C runtime to load test classes and find test methods, etc.
Swift generic classes are not compatible with Objective-C. See https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID53:
When you create a Swift class that descends from an Objective-C class, the class and its members—properties, methods, subscripts, and initializers—that are compatible with Objective-C are automatically available from Objective-C. This excludes Swift-only features, such as those listed here:
Generics
...
Ergo your generic XCTestCase subclass can not be used by XCTest.
Well, actually its totally doable. You just have to create a class that will be sort of test runner. For example:
class TestRunner: XCTestCase {
override class func initialize() {
super.initialize()
let case = XCTestSuite(forTestCaseClass: ViewControllerTests<WelcomeViewController>.self)
case.runTest()
}
}
This way you can run all your generic tests.
I got it working in a kind of hacky way with protocols & associated types:
import XCTest
// If your xCode doesn't compile on this line, download the lastest toolchain as of 30 november 2018
// or change to where Self: XCTestCase, and do it also in the protocol extension.
protocol MyGenericTestProtocol: XCTestCase {
associatedtype SomeType
func testCallRunAllTests()
}
extension MyGenericTestProtocol {
// You are free to use the associated type here in any way you want.
// You can constraint the associated type to be of a specific kind
// and than you can run your generic tests in this protocol extension!
func startAllTests() {
for _ in 0...100 {
testPrintType()
}
}
func testPrintType() {
print(SomeType.self)
}
}
class SomeGenericTestInt: XCTestCase, MyGenericTestProtocol {
typealias SomeType = Int
func testCallRunAllTests() {
startAllTests()
}
}
class SomeGenericTestString: XCTestCase, MyGenericTestProtocol {
typealias SomeType = String
func testCallRunAllTests() {
startAllTests()
}
}
This approach (https://stackoverflow.com/a/39101121/311889) no longer works. The way I did it in Swift 5.2 is:
class MyFileTestCase: XCTestCase {
override func run() {
let suite = XCTestSuite(forTestCaseClass: FileTestCase<MyFile>.self)
suite.run()
super.run()
}
// At least one func is needed for `run` to be called
func testDummy() { }
}

Compiler error when assigning the Delegate for a Protocol in Swift iOS

I have a problem assigning the delegate for an object that is an instance of a class that defines a protocol in Swift as follows:
I simplified the code to the bare bones to exemplify the issue:
This is the class with the protocol
protocol TheProtocol {
func notifyDelegate()
}
class ClassWithProtocol: NSObject {
var delegate: TheProtocol?
fire() {
delegate?.notifyDelegate()
}
}
This is the class the conforms to the Protocol
class ClassConformingToProtocol: NSObject, TheProtocol {
var object: ClassWithProtocol?
func notifyDelegate() {
println("OK")
}
init() {
object = ClassWithProtocol()
object?.delegate = self // Compiler error - Cannot assign to the result of this expression
object?.fire()
}
}
I have tried all sort of alternatives to assign the delegate without success. Any idea what I am missing?
The Known Issues section of the Release Notes says:
You cannot conditionally assign to a property of an optional object.
(16922562)
For example, this is not supported:
let window: NSWindow? = NSApplication.sharedApplication.mainWindow
window?.title = "Currently experiencing problems"
So you should do something like if let realObject = object { ... }

Resources