I have this sample protocol having a default valued property with extension.
protocol SampleProtocol{
var sample:String?{get set}
}
extension SampleProtocol{
var sample:String?{ get { return nil } set{} }
}
Now, my TestClass implements SampleProtocol as below.
class TestClass:SampleProtocol {
var sample: String?{
return "TestClass"
}
}
And there's one helper method that prints a sample value from the SampleProtocol.
func printValue(_ value: SampleProtocol){
print(value.sample)
}
Now the problem is
let testObj = TestClass()
print(testObj.sample) // prints "TestClass"
printValue(testObj) // prints nil
From the above result, I need to understand why when the testObj is typecasted into SampleProtcol, it is considering default implementation from extension instead of the implementation from the TestClass?
The problem is that the TestClass is not implementing the SampleProtocol so when you pass it in the printValue method that takes a SampleProtocol, it will call the default implementation in the protocol extension(since the instance you pass does not implement the protocol method).
In the SampleProtocol you have defined the variable as {get set} but in the TestClass variable you have only provided a getter, this does not match the requirements (If you remove the protocol extension you will see an error that the class does not conform to the protocol).
It will work if you provide a setter:
class TestClass: SampleProtocol {
var sample: String? {
get {
return "TestClass"
} set { }
}
}
Related
I'm trying to learn protocols and associatedtypes. I have couple of protocols which declare associatedtypes, starting with:
protocol MasterViewModel {
associatedtype Item: AWMediaItem
...
}
AWMediaItem is another protocol
protocol AWMediaItem {
var name: String { get }
var source: AWMediaSource { get }
}
And AWAlbum is yet another protocol which inherits from AWMediaItem
protocol AWAlbum: AWMediaItem {
var albumName: String { get }
...
}
For some reason, in a class implementing MasterViewModel protocol, I cannot set the AWAlbum to be the Item.
final class AlbumsMasterViewModel: MasterViewModel {
typealias Item = AWAlbum // Error
...
}
The warning I get is
Possibly intended match 'AlbumsMasterViewModel.Item' (aka 'AWAlbum') does not conform to 'AWMediaItem'
If I understand correctly, all AWAlbum's will implement AWMediaItem so why is this not working?
I think you meant to write
final class AlbumsMasterViewModel<Item: AWAlbum>: MasterViewModel {
}
I assume that when you write :
typealias Item = AWAlbum // Error
you want AlbumsMasterViewModel's item to conform to your AWAlbum protocol but you just create a typelias meaning that Item is just an alias for AWAlbum .
If you want to use a type alias you need a concrete type conforming to AWMediaItem, not a protocol inheriting from it. eg :
class ConcreteAlbum: AWAlbum {
var albumName: String
var name: String
var source: AWMediaSource
...
}
final class AlbumsMasterViewModel: MasterViewModel {
typealias Item = ConcreteAlbum // No Error
}
Edit
if you want to use AlbumsMasterViewModel with multiple Item types you can also declare it that way :
final class AlbumsMasterViewModel<Item: AWMediaItem>: MasterViewModel {
}
I want to add a generic parameter for all collection type that has isEmpty so they can also have isNotEmpty When I try to make Collection conform to Occupiable I got an compile error
error here : Extension of protocol 'Collection' cannot have an inheritance clause
also String conform to a protocol that inherent from Array so can we just remove extension String: Occupiable { } once we found a solution for the issue above ?
// Anything that can hold a value (strings, arrays, etc)
protocol Occupiable {
var isEmpty: Bool { get }
var isNotEmpty: Bool { get }
}
// Give a default implementation of isNotEmpty, so conformance only requires one implementation
extension Occupiable {
var isNotEmpty: Bool {
return !isEmpty
}
}
extension String: Occupiable { }
// error here : Extension of protocol 'Collection'
// cannot have an inheritance clause
extension Collection: Occupiable { }
You need to set a constraint on conformance.
This will fix the error.
extension Collection where Self: Occupiable { }
Here you have created Occupiable protocol with isEmpty and isNotEmpty variables
so when we implement protocol in any class these two variable need to declare to fullfill protocol. but here you already declare isNotEmpty variable inside Occupiable's extension so now only one isEmpty compulsory in class where we implement protocol.
so isEmpty inside Collection Protocol so we need to extend protocal. but it work in String because string is struct .
you need to code for Collection like:
extension Collection where Self : Occupiable {}
protocol BasePresenterProtocol : class {}
protocol DashboardPresenterProtocol : BasePresenterProtocol {}
final class DashboardPresenter {
weak var view: DashboardPresenterProtocol?
init() {
self.view = DashboardViewController()
}
func test() {
print("Hello")
}
}
extension DashboardPresenter: DashboardViewProtocol { }
protocol BaseViewProtocol : class {
weak var view: BasePresenterProtocol? { get set }
}
protocol DashboardViewProtocol : BaseViewProtocol {
}
class DashboardViewController {
}
extension DashboardViewController: DashboardPresenterProtocol { }
In the above code, I get an error at following line
extension DashboardPresenter: DashboardViewProtocol { }
that, DashboardPresenter doesn't confirm to protocol DashboardViewProtocol, but I have declared weak var view: DashboardPresenterProtocol? in DashboardPresenter . Although I have declared
Why am I getting this error ? Please let me know what I am doing wrong in this code.
You cannot implement a read-write property requirement of type BasePresenterProtocol? with a property of type DashboardPresenterProtocol?.
Consider what would happen if this were possible, and you upcast an instance of DashboardPresenter to DashboardViewProtocol. You would be able to assign anything that conforms to BasePresenterProtocol to a property of type DashboardPresenterProtocol? – which would be illegal.
For this reason, a read-write property requirement has to be invariant (although it's worth noting that a readable-only property requirement should be able to be covariant – but this currently isn't supported).
This question already has answers here:
Overriding superclass property with different type in Swift
(15 answers)
Closed 6 years ago.
I have A class. And its subclass B. I need to override type of its property. Also that will be ok to to change a protocol. How can I do that?
class A {
var property: String (or SomeProtocolA)
}
class B: A {
var property: Int (or SomeProtocolB)
}
Maybe its possible to add support second protocol for property in subclass?
You can't, and this is indicative of poor design.
Suppose Class A had a function:
class A {
var property: String (or SomeProtocolA)
func getMyString() -> String {
return property
}
}
and now class B inherits it, whilst "overwriting" property:
class B : A {
var property: Int(or SomeProtocolB)
// func getMyString() -> String { //inherited from superclass
// return property //type error, expected String, returning Int
//}
}
You can do this, but in VERY limited situations. The only ways that this is allowed is under the following circumstances:
The property must be get only.
The overriding type must be a subclass of the original type (so no struct, protocol or enum).
Here is an example overriding with strings:
class A {
var property: NSString {
return ""
}
}
class B: A {
override var property: NSMutableString {
return NSMutableString(string: "")
}
}
Why declare readonly property in protocol if we can set value trough class or struct? I can not understand usage of this.
In "The Swift Programming Book" version 2.0
“If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for the property to be also settable if this is useful for your own code.”
So that it's not settable from outside the class/struct. Imagine your API returned some instance of a protocol that has a get and set property (in your protocol), then anyone getting this instance would be able to set the value!
Also get and set properties can't be constants:
protocol RWProt {
var value : Int { get set }
}
// Error: Type 'Value' does not conform to protocol 'RWProt'
struct Value : RWProt {
let value = 0
}
This however works:
protocol Read {
var value : Int { get }
}
struct Value : Read {
var value = 0
mutating func change() {
value++
}
}
The protocol only needs the value to be gettable, so get protocols properties are not get only but rather get or set
Okay, here is another example:
import Foundation
public protocol ExternalInterface {
var value : Int { get }
}
private struct PrivateStuff : ExternalInterface {
var value = 0
mutating func doSomePrivateChangingStuff() {
value = Int(arc4random())
}
}
public func getInterfaceToPrivateStuff() -> ExternalInterface {
var stuff = PrivateStuff()
stuff.doSomePrivateChangingStuff()
return stuff
}
// In another file:
let interfaceToSomethingICantChange = getInterfaceToPrivateStuff()
// error: cannot assign to property: 'value' is a get-only property
interfaceToSomethingICantChange.value = 0