所以我是iOS开发的新手,在我的实习期间一直在对一个具有相对较大objective-c代码库的应用程序进行微小的更改。我一直在从Treehouse学习快速(哇,爱他们!),我刚刚了解了协议。目前,它们应该在某些情况下使用,教师使用了此示例。
假设您有一家公司,有两种不同类型的员工:薪水和小时(很常见)。现在,它们都将从一个名为 Employee 的超类继承,并且都必须调用一个名为"pay"的函数来支付员工。如何强制实施这些类来实现该函数?当然,使用协议,但这需要您记住将其添加到函数声明中。有没有办法将协议添加到超类"Employee"中,然后从该类继承的任何内容都必须遵循该超类的协议。有没有其他方法可以做到这一点?谢谢!
你要找的是一个抽象类。 抽象类的目的是充当要从中继承的具体类的基类,但抽象类不能直接实例化。
如果Employee
是一个抽象类,那么任何实际实例化Employee
实例的尝试都将被编译器报告为错误。 你需要实例化一个具体的Employee
子类,例如SalariedEmployee
或HourlyEmployee
。
Employee
类的定义将包括需要calculatePay
方法,如果具体子类未实现该方法,则再次发生编译时错误。
现在,坏消息。 Objective-C 和 Swift 都不支持抽象类。
可以通过提供方法的实现来提供类似的类,如果该方法未被子类重写,则会引发异常。 这会产生运行时错误,而不是编译时错误。
例如
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()
}
}
不幸的是,尚不支持abstract
函数。一种可能的解决方法是在子类未覆盖此类函数时启动fatalError
,这样做:
protocol YourProtocol {
func pay()
}
class Employee: YourProtocol {
func pay() {
fatalError("Must Override")
}
}
class SubEmployee: Employee {
func pay() {
print("stuff here")
}
}
我的方法是将委托作为参数包含在类初始值设定项中。 请参阅下面的代码:
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#>)
}
}