5

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!

3 Answers 3

6

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() } } 
Sign up to request clarification or add additional context in comments.

3 Comments

This would be the closest thing that I’m referring to, thank you so much! Very clear explanation as well and I’ll try what you suggested. Hopefully they add the feature of abstract classes soon.
There is a Swift Evolution proposal for abstract but it is currently deferred.
Interesting. I knew it was open source and this would be great. I haven’t learned about protocol extensions so hopefully that’ll help me out as well.
3

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

1 Comment

This was a suggestion the other person suggested, thanks!
0

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#>) } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.