美文网首页
iOS开发-在 UIKit 控件中使用动作闭包

iOS开发-在 UIKit 控件中使用动作闭包

作者: iOS丶lant | 来源:发表于2022-04-26 13:50 被阅读0次

说到 iOS 上的用户界面实现,那么 SwiftUI 就是现在每个人脑海中浮现的框架。SwiftUI 一天比一天吸引更多的开发者,并且一年比一年增加新的功能和可能性。但是,这并不意味着 UIKit 框架已经属于过去;相反,UIKit 在可预见的未来很长一段时间内都会存在,并将继续存在。

所以,在每一次 WWDC 中,除了所有让我们兴奋的关于 SwiftUI 的新闻外,还有关于 UIKit 的公告和改进。而这样的 UIKit 新特性就是今天这篇文章所要讨论的。

UIKit 最初与 iOS 14 一起出现在 WWDC 2020 中,它可以避免使用我们多年来熟悉的目标动作模式;当用户与 UIKit 控件交互时,需要指定要调用的选择器方法。相反,我们可以使用闭包,因此将控件的操作与其初始化和配置保持在一起。

下面的几个例子将完全清楚我在说什么。如果您还没有意识到这种技术,那么我敢打赌,在阅读完这篇文章后您会发现它非常有趣。

目标行动模式

当使用 UIKit 实现用户界面时,我们可以采取两种方式;使用故事板和 XIB 文件的图形,或以编程方式制作。选择前一种方法时,有必要实现特殊操作方法并将其连接到提供用户交互的控件。这些方法用@IBAction关键字标记,当它们的匹配控件触发某些事件时调用它们。

以编程方式构建用户界面时发生的场景非常相似。为了开始讨论一些代码示例,请参阅以下几行初始化和配置 UIButton:

override func viewDidLoad() {
   super.viewDidLoad()
   
   let button = UIButton(type: .system)
   button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)

   // Additional button configuration...
}

这里有趣的一行是按钮初始化之后的那一行。它说的很简单;将类(UIView、UIViewController)的当前实例视为查找按钮操作(目标)的位置。实际行动就是buttonAction()方法。当事件发生时调用它touchUpInside,这意味着当用户抬起按钮的手指时。

然而,这还不够。为了真正制作buttonAction()一个动作方法,也称为选择器方法,需要用@objc关键字标记它:

@objc
func buttonAction() {
   // Do something when the button is tapped...
}

这种表示法在 Swift 中继承自旧的良好 Objective-C,以及刚刚提出的整个目标-动作模式。这里真正的缺点是需要定义一个额外的方法来实现按钮的动作。作为一个自然的子序列,控件越多,我们必须实现的选择器方法就越多。不可避免地,这会导致可读性和可维护性问题,尤其是在大型代码库中。

使用闭包代替选择器方法

值得庆幸的是,自从 iOS 14 以来,事情会变得更好、更简单。可以遵循替代路线,并使用闭包而不是选择器方法。您很快就会意识到,当实现的操作只需要几行代码时,这非常方便。但这不是一个严格的规则。闭包方法可用于小型和大型实现。

是时候看看这一切的第一个例子了。我们将从UIAction这样初始化一个对象开始:

let action = UIAction { _ in
    print("Hello there!")
}

注意: UIAction 看起来很眼熟吗?如果你曾经用 UIKit 展示过一个 action sheet,那么你肯定遇到过它。

在上面的代码片段中,我们初始化了一个UIAction实例并将其分配给action常量。我们提供给它的参数是我们想要在我们接下来创建的按钮被点击时调用的闭包。

下一步是初始化 UIButton,将上述操作作为参数传递:

let button = UIButton(primaryAction: action)

注意:提供按钮类型是可选的。如果我们在此处省略它,则.system默认使用按钮样式。

以上就是我们对用户交互做出反应所需要的一切!无需创建额外的选择器方法,或指定self为目标。当然,为了将按钮添加到视图、设置样式等,应该在真实的应用程序中进行额外的配置。

在上面的两个后续步骤中,我使用闭包和按钮初始化了动作。这是故意的,也是出于演示的原因。实际上,两者都可以,而且为了节省空间,应该在一个步骤中结合起来。下面的代码演示了一个自定义类型的按钮的初始化。提供的 UIAction 使用内联的动作闭包进行初始化:

let button = UIButton(type: .custom, primaryAction: UIAction(handler: { _ in
   print("Hello there!")
}))

使用带有更多 UIKit 控件的闭包

最有可能的是,按钮将成为您最常与闭包一起使用的 UIKit 控件。但是,闭包也可以与其他控件一起使用,我们将在这里看到其中的几个。

第一个将是 UISwitch。这是一个很好的例子,可以发现新事物;如何在控件初始化后为 UIAction 实例提供闭包。在下一个片段中查看addAction(_:for:)方法;它接受动作闭包,以及一个附加值,即触发闭包调用的事件:

let switchControl = UISwitch()
switchControl.addAction(UIAction(handler: { _ in
   // Do something when the switch is toggled...
}), for: .valueChanged)

尽管以上对于大多数情况来说已经足够了,但有时您需要访问闭包内的实际控件。参考上面的例子,那将是 switch 实例。

我们可以很容易地得到控件的引用;它是闭包的参数值,到目前为止,我在之前的所有示例中都用下划线符号替换了它。这个值是 UIAction 实例,它有一个名为sendertype的属性Any。我们只需要将其转换为控件的类型即可使用它。

以下示例演示了所有这些:

let switchControl = UISwitch()
switchControl.addAction(UIAction(handler: { action in
   guard let control = action.sender as? UISwitch else { return }
   let state = control.isOn ? "on" : "off"
   print("Switch is \(state)")
}), for: .valueChanged)

除了上述所有内容之外,UIKit 控件还具有允许提供动作闭包和另一个值的初始化程序。例如,接下来的开关使用作为第一个参数给出的帧进行初始化:

let rect = CGRect(x: 0, y: 60, width: 100, height: 44)
let switchControl = UISwitch(frame: rect, primaryAction: UIAction(handler: { _ in
   
}))

可以像上面演示的 UISwitch 一样创建和处理更多控件。接下来您可以看到一个类似的示例,但这次使用的是 UITextField。动作闭包是通过addAction(_:for:)方法给出的,指定的事件不同:

let textField = UITextField()
textField.addAction(UIAction(handler: { action in
   guard let textField = action.sender as? UITextField else { return }
   print(textField.text)
}), for: .editingChanged)

结论

在 UIKit 控件中使用动作闭包而不是目标动作模式似乎真的很方便。但是,如果我们有多个控件,并且每个动作闭包内部会有 10-15 行代码和额外的配置代码,该怎么办?所有这些的容器方法最终会变得很长,难以阅读且难以维护。在这种情况下,坚持我们已经知道的目标-动作模式可能是一个更可取的解决方案。但最终,您最终会选择哪种方法完全取决于您。现在您了解了 UIKit 控件中的动作闭包,因此请考虑将您在此处阅读的内容作为工具带中的另一个工具,并在合适的时候将其投入使用。我希望你觉得这篇文章很有趣,谢谢你的阅读!

这里也推荐一些面试相关的内容,祝各位网友都能拿到满意offer!
GCD面试要点
block面试要点
Runtime面试要点
RunLoop面试要点
内存管理面试要点
MVC、MVVM面试要点
网络性能优化面试要点
网络编程面试要点
KVC&KVO面试要点
数据存储面试要点
混编技术面试要点
设计模式面试要点
UI面试要点

相关文章

网友评论

      本文标题:iOS开发-在 UIKit 控件中使用动作闭包

      本文链接:https://www.haomeiwen.com/subject/vpgcyrtx.html