所以我是iOS开发的新手,并且在我的实习中对应用程序进行了一些小的更改,这个实例具有相对较大的Objective-c代码库。我一直在树屋学习(哇,爱他们!),我刚刚学习了协议。目前,它们应该在某些情况下使用,教师使用这个例子。
假设您的公司有两种不同类型的员工:薪水和每小时(很常见)。现在,他们都将继承一个名为Employee的超级类,并且两者都必须调用一个名为“pay”的函数来支付员工的工资。您如何强制执行这些类来实现该功能?当然,使用协议但这需要您记住将其添加到函数声明中。有没有办法将协议添加到超类“Employee”,然后从该类继承的任何内容都必须遵循该超类的一部分协议。还有另一种方法吗?谢谢!
答案 0 :(得分:3)
您正在寻找的是抽象类。 抽象类的目的是作为继承的具体类的基类,但是不能直接实例化抽象类。
如果Employee
是一个抽象类,那么实际实例化Employee
实例的任何尝试都将被编译器报告为错误。您需要实例化Employee
的具体子类,例如SalariedEmployee
或HourlyEmployee
。
Employee
类的定义将包括需要calculatePay
方法,如果具体的子类没有实现该方法,则会再次出现编译时错误。
现在,坏消息。 Objective-C和Swift都不支持抽象类。
您可以通过提供一个方法的实现来提供类似的类,如果它没有被子类覆盖,则该方法会抛出异常。这会产生运行时错误而不是编译时错误。
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
}
}
calculatePay
是基类的一部分还是通过增加协议一致性的扩展分配给基类,结果是相同的;
Employee
类需要一个生成某种错误的函数的默认实现你可以单独为每个子类分配一个协议,比如Payable
,但是由于协议不是基类的一部分,你不能说:
var employees[Employee]
for e in employees {
let pay = e.calculatePay()
}
你必须使用稍微复杂一些:
for e in employees {
if e is Payable {
let pay = e.calculatePay()
}
}
答案 1 :(得分:1)
不幸的是,abstract
函数尚不支持。一个可能的解决方法是在子类未覆盖此类函数时启动fatalError
,这样做:
protocol YourProtocol {
func pay()
}
class Employee: YourProtocol {
func pay() {
fatalError("Must Override")
}
}
class SubEmployee: Employee {
func pay() {
print("stuff here")
}
}
答案 2 :(得分:0)
我的方法是将委托作为参数包含在类初始值设定项中。看下面的代码:
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#>)
}
}