我何时以及为啥要在 Swift 中使用协议?

Posted

技术标签:

【中文标题】我何时以及为啥要在 Swift 中使用协议?【英文标题】:When and why would i use Protocols in Swift?我何时以及为什么要在 Swift 中使用协议? 【发布时间】:2019-04-21 01:21:45 【问题描述】:

所以我遇到了协议这个主题,我在互联网上搜索了很多答案,但我找不到一个,至少一个解决了我的问题。

所以我明白协议是方法、属性等的“蓝图”,它可以在类或结构中实现,并且需要符合其要求等,但为什么要使用呢?

我的意思是你也可以在结构本身内创建一个函数。编写协议似乎有点麻烦,然后为了实现所述协议,这次您必须使用更多代码再次编写所有需求。

使用协议是否有特殊原因?是为了代码安全还是其他原因?

例如:

在 swift 中,您拥有 CustomStringConvertible 协议,该协议具有必需的计算属性来控制自定义类型如何表示为可打印的字符串值,但您也可以在类中创建一个函数来解决这个问题。您甚至可以拥有与此协议相同的计算属性,甚至无需实现此协议。

因此,如果有人能对这个主题有所了解,那就太好了。

提前谢谢你!

【问题讨论】:

因为您可能希望能够使用多个不同的实现类,它们都实现了相同的方法。查找 Java 接口的理由,因为目的相同。 您可以使用协议来允许根本不需要链接的不同类(没有相同的用途,相同的父类)来强制它们具有某些方法。 可能相关:***.com/questions/46496485/… What is Protocol Oriented Programming in Swift? What added value does it bring?的可能重复 也是半相关的:***.com/questions/41706504/… 【参考方案1】:

但是为什么要使用一个呢?

Protocols 在 swift 中类似于 Abstractions 在其他一些语言中。

在回答您的问题之前,我们必须先澄清一下,Protocols 声明可能多种多样,但考虑到您已经阅读了大量内容,

很高兴提及这个答案here。

现在让我们进入真正的用例。

假设你有这个协议。

protocol Printable 
var name: String  get 

现在我们需要某种类型的structsclasses 来确认它,或者多个

这是它最大的好处之一。

考虑您必须打印对象的name 属性。

例如那些。

struct Human 
    var name: String

struct Animal 
    var name: String

不用Protocols,你只需输入这个

    func printOut(human: Human)
    human.name
   

   func printOut(animal: Animal)
    animal.name    
   

哪个是正确的,现在使用协议Printable观察下面的代码。

struct Human: Printable 
    var name: String

struct Animal: Printable 
    var name: String


 func printOut(object: Printable)
    print(object.name)
   

我们只需要一个func 等等使用Protocols

结论

用于最小化不必要的代码块的协议。

它的名字代表了应用在确认方上的效果。

协议可以作为参数类型注入。

您还可以阅读更多关于他们的信息here。

更多关于用例here。

【讨论】:

【参考方案2】:

协议的概念非常简单:它只不过是一个承诺,即特定方法和/或属性将存在于该协议所采用的任何对象中。因此,我们将它们用于打字和打字安全。

想象一下创建一个自定义控件,例如操作表:

class CustomActionSheet: UIControl 

    func userTappedOnSomething() 
        // user tapped on something
    


...您在其中一个视图控制器中实现了它。

class SomeViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()
        let actionSheet = CustomActionSheet()
    


当用户点击按钮时,如果不让操作表与视图控制器通信,这并没有多大用处。所以我们使用委托:

class CustomActionSheet: UIControl 

    weak var delegate: UIViewController?

    func userTappedOnSomething() 
        delegate?.userTookAction()
    



class SomeViewController: UIViewController 

    override func viewDidLoad() 
        super.viewDidLoad()

        let actionSheet = CustomActionSheet()
        actionSheet.delegate = self

    

    func userTookAction() 
        // update the UI
    


现在,当用户点击操作表中的按钮时,下方的视图控制器可以更新其 UI。但这实际上不会编译。您将收到 UIViewController 没有成员 userTookAction 的错误。那是因为UIViewController 类没有名为userTookAction 的方法,只有视图控制器的这个实例有。所以我们使用一个协议:

protocol ActionSheetProtocol: AnyObject 
    func userTookAction()

这个协议说任何符合它的对象都必须包含这个方法。因此,我们将操作表的委托更改为该协议类型,并且我们使视图控制器符合该协议,因为它具有这样的方法:

class CustomActionSheet: UIControl 

    weak var delegate: ActionSheetProtocol?

    func userTappedOnSomething() 
        delegate?.userTookAction()
    



class SomeViewController: UIViewController, ActionSheetProtocol 

    override func viewDidLoad() 
        super.viewDidLoad()

        let actionSheet = CustomActionSheet()
        actionSheet.delegate = self

    

    func userTookAction() 
        // update the UI
    


这是一个在 Swift 中使用协议的经典例子,一旦你理解了它,你将学会如何巧妙地使用协议并以非常聪明的方式使用它们。但无论你如何使用它们,概念仍然存在:承诺事物将存在。

注意:在本例中,我将协议命名为ActionSheetProtocol,因为对于学习协议的人来说,它最有意义。然而,在 Swift 世界中,在今天的实践中,大多数程序员(包括 Apple 的人)会将其命名为 ActionSheetDelegate。这可能会让学习协议的人感到困惑,所以在这个例子中,我试图让它尽可能清晰。我个人不喜欢命名协议代表,但有很多我不喜欢的东西。

注意 2: 我还创建了 AnyObject 类型的协议,这是 Swift 使协议成为类协议的语法。并非所有协议都必须是 AnyObject 类型。

【讨论】:

【参考方案3】:

Swift 中的协议是一种允许您的类确认特定规则集的模式。

换句话说,协议是特定任务所需的方法和属性的蓝图。

您通过确认协议来实施协议。如果您的类错过了协议中定义的任何方法的实现,swift 编译器会告诉您。

作为一个例子,让我们考虑你想要创建一个 Car 类。现在对汽车有特殊要求。就像它有***、行李箱等一样。每个需求都可以定义为一个协议,然后由 Car 类实现。如果您的班级没有主干,您只需放弃实现即可。

面向协议的编程是一种新的编程范式。这解决了面向对象编程引起的一些问题。比如多重继承。 Swift 不允许多重继承,但它允许对多个协议进行确认。

在面向协议的编程中,从类中删除某些功能非常容易。你只是停止遵守它。与 OOP 相比,在 POP 中做这些事情非常容易。

【讨论】:

以上是关于我何时以及为啥要在 Swift 中使用协议?的主要内容,如果未能解决你的问题,请参考以下文章

使用 jQuery 时何时/为啥要在变量前加上“$”? [复制]

Swift 委托 - 何时在委托上使用弱指针

为啥我不能在 Swift 中使用 let in 协议?

何时以及为啥需要在 C++ 中使用 cin.ignore()?

为啥以及何时使用重组分支?

为啥我们需要复制构造函数以及何时应该在 java 中使用复制构造函数