Protocol Conformance of "Inherited" Property [duplicate] - ios

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).

Related

Understanding Swift default valued properties inside a Protocol extension

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 { }
}
}

Setting protocol which inherits from another protocol as associated type produces error

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 {
}

Add protocol to super class which will force other classes that inherit from it to implement protocol

So I'm new to iOS development and have been working on minor changes to an app at my internship that has a relatively large objective-c code base. I've been learning swift from Treehouse(Wow, love them!) and I just learned about protocols. Currently, they should be used in certain instances and the instructor used this example.
Say you have a company with two different types of employees: Salary and Hourly(Pretty common). Now, they both would inherit from a super class called Employee and both would have to call a function called "pay" which would pay the employee. How do you enforce these classes to implement that function? Sure, use a protocol but that would require you to remember to add that to the function declaration. Is there a way to just add the protocol to the super class "Employee" and then whatever inherits from that class would have to follow that protocol that's part of that superclass. Is there another way to do this? Thanks!
What you are looking for is an abstract class. The purpose of an abstract class is to behave as a base class for concrete classes to inherit from, but an abstract class cannot be instantiated directly.
If Employee was an an abstract class then any attempt to actually instantiate an instance of Employee would be reported as an error by the compiler. You would need to instantiate a concrete subclass of Employee, such as SalariedEmployee or HourlyEmployee.
The definition of the Employee class would include that the calculatePay method was required and again a compile time error would occur if a concrete subclass did not implement that method.
Now, the bad news. Neither Objective-C nor Swift supports abstract classes.
You can provide a similar kind of class by providing an implementation of a method that throws an exception if it isn't overridden by a subclass. This gives a runtime error rather than a compile time error.
e.g.
class Employee {
var givenName: String
var surname: String
...
init(givenName: String, surname: String) {
self.givenName = givenName
self.surname = surname
}
func calculatePay() -> Float {
fatalError("Subclasses must override calculatePay")
}
}
class SalariedEmployee: Employee {
var salary: Float
init(givenName: String, surname: String, annualSalary: Float) {
salary = annualSalary
super.init(givenName: givenName, surname: surname)
}
override func calculatePay() -> Float {
return salary/12 // Note: No call to super.calculatePay
}
}
Whether the calculatePay is part of the base class or assigned to the base class through an extension that adds conformance to a protocol, the result is the same;
The Employee class will need a default implementation of the function that generates some sort of error
Failure of a subclass to implement the method will not cause a compile time error
You could assign a protocol, say, Payable to each subclass individually, but then as the protocol was not part of the base class, you couldn't say something like:
var employees[Employee]
for e in employees {
let pay = e.calculatePay()
}
You would have to use the slightly more complicated:
for e in employees {
if e is Payable {
let pay = e.calculatePay()
}
}
Unfortunately abstract functions are not yet supported. A possible workaround is to launch a fatalError when such function is not overridden by a subclass, doing so:
protocol YourProtocol {
func pay()
}
class Employee: YourProtocol {
func pay() {
fatalError("Must Override")
}
}
class SubEmployee: Employee {
func pay() {
print("stuff here")
}
}
My approach to this is to include the delegate as a parameter in the class initializer. See the code below:
protocol ProtocolExample {
func somethingNeedsToHappen()
}
// typical class example with delegate property for the required protocol
class ClassExampleA {
var delegate: ProtocolExample!
init() {
}
func aCriticalMethodWithUpdates() {
delegate.somethingNeedsToHappen()
}
}
// use class example in a view controller. Can easily forget to invoke the delegate and protocol
class MySampleViewControllerA: UIViewController {
var classExampleA : ClassExampleA!
func loadMyData() {
classExampleA = ClassExampleA()
}
}
// an alternative approach for the class is to include the delegate parameter in the initializer.
class ClassExampleB {
var delegate: ProtocolExample!
init(delegateForUpdates: ProtocolExample) {
delegate = delegateForUpdates
}
func doSomething() {
delegate.somethingNeedsToHappen()
}
}
// go to use it and you're reminded that the parameter is required...
class MySampleViewControllerB: UIViewController {
var classExampleB: ClassExampleB!
func loadMyData() {
classExampleB = ClassExampleB() // error: Missing argument for parameter 'delegateForUpdates' in call
}
}
// so to avoid error:
class MySampleViewControllerC: UIViewController {
var classExampleB: ClassExampleB!
func loadMyData() {
classExampleB = ClassExampleB(delegateForUpdates: <#ProtocolExample#>)
}
}

Class does not conform to protocol

This is my protocol:
protocol LiveTableViewCellProtocol: class {
var data: LiveCellObjectProtocol! { get set }
}
This is my class:
class RepliesTableViewCell: UITableViewCell, LiveTableViewCellProtocol {
var data: RepliesCellObject! //ERROR! does not conform to protocol.
}
RepliesCellObject is defined as:
public class RepliesCellObject: NSObject , LiveCellObjectProtocol{
//basic stuff here.
}
RepliesCellObject is a LiveCellObjectProtocol ... so why doesn't my table cell conform?
It doesn't conform because in an object that conforms to LiveTableViewCellProtocol, you can set data to any LiveCellObjectProtocol, including one that isn't an NSObject. In RepliesTableViewCell, you can't do that. The data must be set to a LiveCellObjectProtocol that is also an NSObject.
Therefore RepliesTableViewCell doesn't conform to LiveTableViewCellProtocol.
It must specifically be the same as the protocol says. What you're doing is not allowed because it is not the exact same. Remember, you can use as! to make it a RepleisCellObject if you're sure it is.
associatedtype can help here
protocol LiveTableViewCellProtocol: class {
associatedtype Data: LiveCellObjectProtocol
var data: Data! { get set }
}
You should use associated type
protocol LiveTableViewCellProtocol: class {
associatedtype Object : LiveCellObjectProtocol
var data: Object! { get set }
}

Swift and property inheritance from superclass [duplicate]

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: "")
}
}

Resources