iOS初学者代表

iOS开发的大多数初学者在理解委托人时都有问题。 苹果公司说,委托是一个对象,当另一个对象遇到程序中的事件时,该对象代表另一个对象或与另一个对象协同工作。 为简化起见,委托是一个对象,它允许对象A和对象B使用函数或变量相互通信。 代表由程序中的事件触发(例如,按下按钮)。

让我在一个将数据从自定义视图传输到视图控制器的简单示例中为您解释一下。

让我们从创建一个新的Xcode项目开始; 所以打开Xcode,选择Create a new Xcode project

选择Single View App,然后按Next。

在产品名称字段中,输入DelegateExample,然后按下一步->创建。

好的,现在我们已经建立了一个项目,可以开始了。

现在我们需要创建一个代表对象B的自定义视图。我们的对象A将是View Controller,并且已经由Xcode创建。 因此,要创建自定义视图,请导航到Xcode窗口左侧的项目树,右键单击Delegate Example文件夹,然后单击“新建文件”。

选择Swift文件,然后单击Next。

在另存为字段中输入CustomView,然后按创建

现在,我们将为CustomView创建一个.xib文件。 为此,再次右键单击Delegate Example文件夹,然后选择New File…,但是这次选择View并按Next。 再次将文件命名为CustomView,然后单击“创建”。

现在,您应该在项目树中看到一个CustomView.xib文件,并且应该有一个类似于以下内容的屏幕。

好的,进入代码。 打开您的CustomView.swift文件并为我们的自定义视图创建一个类。 为此,只需在文件中键入此代码即可。

 进口基金会 
导入UIKit
 类CustomView:UIView { 
  } 

现在,我们需要在.xib文件的视图中添加一个类。 导航到CustomView.xib,然后在“检查器”选项卡的顶部选择“身份检查器”。在“类”字段中,输入CustomView,然后按Enter。

现在,在屏幕上的某处添加一个按钮和文本字段。 我将像这样将它们添加到屏幕的中央。

现在回到代码,我们需要为文本字段和按钮创建出口。 为此,请将此代码添加到CustomView类。

  @IBOutlet弱var textField:UITextField! 
@IBOutlet弱变量按钮:UIButton!

现在,将插座与.xib文件中视图内部的文本字段和按钮相连。 为此,请再次导航到“检查器”,然后选择“连接”检查器。 您将看到我们刚刚创建的两个出口。

要连接它们,只需在插座名称旁边的圆圈上按文本框和按钮,然后将它们拖放到视图中的文本框和按钮即可。

现在,让我们以相同的方式在View Controller中添加标签。 转到ViewController.swift文件,并将此代码添加到ViewController类中。

  @IBOutlet弱var标签:UILabel! 

转到Main.storyboard,向ViewController添加标签和按钮,然后使用检查器连接标签出口。

太好了,现在我们已经设置了对象A和对象B。我们的对象A将是ViewController,而我们的对象B将是CustomView。 现在的想法是在CustomView上的文本中键入内容,然后在ViewController上更改Label的文本。 为此,我们需要一个协议。 因此,让我们创建一个。 返回CustomView类,并将此代码添加到CustomView类上方。

 协议TextTransferDelegate:类{ 
  } 

现在让我们在刚刚添加的协议中声明一个函数。

 协议TextTransferDelegate:类{ 
func transferText(text:String)
}

好的,所以我们知道我们需要将一些数据从一个对象传输到另一个对象。 为此,我们将使用刚刚添加的此功能。 我们知道,我们要传输的数据类型是来自文本字段的简单字符串。 这就是为什么函数中有一个名为“ text”的参数的原因。 我们稍后将使用该参数传递数据。 注意,协议内部没有方法主体。 这是因为协议仅用于声明函数或变量,而不用于实现它们。

现在让我们在CustomView类中创建一个委托属性,只需添加以下代码

 弱var委托:TextTransferDelegate?  =无 

太好了,现在我们有一个名为委托的属性。 之所以将代表声明为弱变量,是为了避免强参考循环(也称为“保留循环”)的风险。 我个人更喜欢将它们设置为可选,稍后我将解释原因。

现在,让我们回到ViewController类并为我们之前添加的按钮做一个动作,以便我们可以呈现我们的自定义视图。

首先,通过将此代码添加到我们的ViewController类中,为我们的自定义视图创建一个属性。

  var customView:CustomView = CustomView() 

之后,我们需要为我们的customView注册笔尖,我们可以通过将以下代码行添加到ViewController类的viewDidLoad()函数中来实现。

  customView =(Bundle.main.loadNibNamed(“ CustomView”,所有者:self,选项:nil)?. first as?CustomView)! 

现在我们可以为按钮创建一个动作,只需添加这部分代码即可

  @IBAction func presentCustomView(_ sender:UIButton){ 
  } 

由于这是一个动作事件,所以请不要忘记将此动作连接到Main.storyboard文件内ViewController上的按钮。 我们可以使用检查员,以与连接插座相同的方式进行操作。

拖放操作,您将获得一个下拉菜单。 选择内部润饰。

现在,动作已连接到按钮。 让我们声明该动作在触发后将执行的操作。 为此,请返回ViewController类,并将这部分代码添加到我们刚刚创建的动作中。

  @IBAction func presentCustomView(_ sender:UIButton){ 
customView.center = self.view.center
self.view.addSubview(customView)
}

尝试构建并运行该应用程序。 按下ViewController上的按钮,您将获得一个新视图,其中显示了文本字段。 这是我们的CustomView。 您可以在文本字段中键入一些文本,但是如何将这些文本传输到ViewController的标签上? 好吧,我们的协议将为我们做到这一点,这就是方法。 首先,我们将实施代表并告诉他该怎么做。

创建ViewController的扩展并像这样继承TextTransferDelegate

 扩展ViewController:TextTransferDelegate { 
  } 

如果您尝试构建项目,则会收到一条错误消息:
“类型’ViewController’不符合协议’TextTransferDelegate’”
还记得我们之前创建的函数“ func transferText(text:String)”吗? 我们需要实现该功能,以便ViewController可以遵循协议。 为此,请添加这部分代码。

 扩展ViewController:TextTransferDelegate { 
func transferText(text:String){
  } 
}

现在,我们的控制器符合协议,但是您可以看到,该功能没有执行任何操作。 现在,让它像这样保留,然后返回CustomView类,并为我们的按钮创建一个动作。 再次简单地添加代码的这一部分,并使用检查器连接动作。

  @IBAction func changeTextPressed(_ sender:UIButton){ 
  } 

当我们按下按钮时,我们想在ViewController上更改标签的文本,而我们的协议应该为我们做到这一点,所以让他告诉他这样做。 将此代码添加到我们刚刚创建的操作中。

  @IBAction func changeTextPressed(_ sender:UIButton){ 
守卫让委托=委托其他{返回}
proxy.transferText(文本:textField.text!)
}

如果尝试构建和运行,请在文本字段中输入一些文本,然后按按钮,则不会发生任何事情。 还记得我说过要解释为什么我更喜欢使代表成为可选人吗? 这行代码:

 守卫让委托=委托其他{返回} 

将防止应用程序崩溃,因为我们没有设置自定义视图委托,并且我们试图从当前为nil的委托中调用一个函数。

  proxy.transferText(文本:textField.text!) 

要解决此问题,我们需要返回ViewController并找到presentCustomView函数。 将此部分添加到代码中:

  customView.delegate =自我 

您最终的presentCustomView函数应如下所示

  @IBAction func presentCustomView(_ sender:UIButton){ 
customView.center = self.view.center
customView.delegate =自我
self.view.addSubview(customView)
}

通过这行代码,我们将委托设置为ViewController,并且我们已经在ViewController类下面的扩展中实现了该协议。 这意味着我们的CustomViews委托是ViewController,因此当

  proxy.transferText(文本:textField.text!) 

被调用,实际上被调用的是(只是为了可视化)

  ViewController.transferText(文本:textField.text!) 

这意味着将调用在ViewController扩展中实现的函数,并将参数“ text”传输到ViewController,并且我们知道“ text”参数的值为textField.text。

现在,您可以看到它是如何工作的,让我们回到扩展中实现的协议功能,并向其中添加一些代码,使其看起来像这样:

 扩展ViewController:TextTransferDelegate { 
func transferText(text:String){
如果文本!=“” {
self.label.text =文字
self.customView.removeFromSuperview()
}
}
}

这里发生了三件事。 第一个是检查参数“ text”是否为空字符串,如果“ text”为空,则什么都不会发生,因此请确保在按CustomView上的按钮之前在textField中输入一些文本。 第二个是协议的实际工作,即将标签文本设置为参数“ text”(textField.text),第三个是删除CustomView窗体ViewController。 这行代码是所有魔术发生的地方。

  self.label.text =文字 

生成并运行项目,然后自己尝试。 一切都应该像魅力一样运作。

这是GitHub上的完整项目。 我希望这会有所帮助,加油!