将协议添加到 super class,这将强制从它继承的其他 classes 实现协议

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

所以我是 iOS 开发的新手,在我的实习期间一直致力于对具有相对较大 objective-c 代码库的应用程序进行细微更改。我一直在从 Treehouse 学习 swift(哇,爱他们!),我刚刚了解了协议。目前,它们应该在某些情况下使用,讲师使用了这个例子。

假设您的公司有两种不同类型的员工:工资和小时工(很常见)。现在,他们都将从一个名为 Employee 的超级 class 继承,并且都必须调用一个名为 "pay" 的函数来支付员工工资。您如何强制执行这些 classes 来实现该功能?当然,使用协议,但这需要您记住将其添加到函数声明中。有没有一种方法可以将协议添加到 super class "Employee",然后从 class 继承的任何东西都必须遵循作为 superclass 一部分的协议。还有另一种方法吗?谢谢!

遗憾的是 abstract 函数尚不支持。一种可能的解决方法是在此类函数未被子类覆盖时启动 fatalError,这样做:

protocol YourProtocol {
  func pay()
}

class Employee: YourProtocol {
  func pay() {
     fatalError("Must Override")
  }
}

class SubEmployee: Employee {
  func pay() {
     print("stuff here")
  }
}

您要查找的是 摘要 class抽象class的目的是充当基础class以供具体class继承,但抽象class 不能直接实例化。

如果 Employee 是一个抽象 class 那么任何试图实际实例化 Employee 实例的尝试都会被编译器报告为错误。您需要实例化 Employee 的具体子 class,例如 SalariedEmployeeHourlyEmployee

Employee class 的定义将包括 calculatePay 方法是必需的,如果具体的子 class 没有,则会再次发生编译时错误实施该方法。

现在,坏消息来了。 Objective-C 和 Swift 都不支持抽象 classes.

您可以通过提供一种方法的实现来提供类似的 class,如果该方法未被子class 覆盖则抛出异常。这给出了运行时错误而不是编译时错误。

例如

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 是基础 class 的一部分还是通过增加协议一致性的扩展分配给基础 class,结果都是一样的;

  • Employee class 将需要生成某种错误的函数的默认实现
  • 子class实现方法失败不会导致编译时错误

您可以为每个子 class 单独分配一个协议,例如 Payable,但是由于该协议不是基础 class 的一部分,您不能说类似于:

 var employees[Employee]

 for e in employees {
     let pay = e.calculatePay()
 }

你必须使用稍微复杂一点的:

 for e in employees {
     if e is Payable {
         let pay = e.calculatePay()
     }
 }

我的方法是将委托作为参数包含在 class 初始值设定项中。请看下面的代码:

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