在本教程中,我们将带你了解Swift中扩展的基本概况。我们将通过建立一个简单的锻炼跟踪应用程序来演示Swift扩展如何工作。
我们将重点介绍以下内容。
什么是 Swift 扩展?
扩展,嗯,扩展现有的Swift命名的类型–即结构、类、枚举和协议–所以你可以向它们添加更多的功能。这使你能够在现有的系统代码中插入你自己的代码,否则你就无法访问这些代码,例如Foundation框架。你也可以使用扩展来扩展你自己的代码,并实现代码的清洁化。
在 Swift 中创建一个扩展
创建扩展与在Swift中创建命名类型类似。当创建一个扩展时,你在名称前添加extension
。
extension SomeNamedType {
// Extending SomeNamedType, and adding new
// functionality to it.
}
复制代码
类型属性
你可以扩展一个特定的命名类型,添加一个新的计算实例,并对其进行类型属性。例如,你可以扩展Color
,给它添加你自己的颜色。比方说,我们的应用程序有一个品牌颜色,我们想在所有地方使用。我们可以通过extension
,扩展Color
,创建一个恒定的类型属性,brand
。
我们的应用程序还在设置屏幕中为行的背景使用自定义颜色。为此,我们将定义一个可变类型的属性,根据系统的外观来调整颜色。
extension Color {
static let brand = Color(red: 75/255, green: 0, blue: 130/255)
static var settingsBackground: Color {
Color(UIColor { (trait) -> UIColor in
return trait.userInterfaceStyle == .dark ? .systemGray5 : .systemGray6
})
}
}
复制代码
下面是如何使用它。
struct SettingsRow: View {
var title: String
var body: some View {
HStack(spacing: 8) {
Text(title)
.foregroundColor(.brand)
Spacer()
Image(systemName: "chevron.right")
}
.foregroundColor(.settingsBackground)
}
}
复制代码
变异方法
正如介绍中提到的,你可以扩展类型来添加你自己的功能,即使你不能访问原始代码库。例如,如果你想给Double
,你可以在结构上写一个扩展,而不必访问Double
结构的原始代码。
在我们的应用程序中,我们正在从HealthKit获取卡路里数据,但该函数返回的数据是Double
类型。我们希望显示四舍五入到小数点后一位的数据。我们可以像这样在Double
,写一个extension
。
extension Double {
mutating func roundTo(places: Int) {
let divisor = pow(10.0, Double(places))
self = (self * divisor).rounded() / divisor
}
}
复制代码
让我们使用这个突变方法来解决我们的问题。
var caloriesBurned: Double? = 213.3244
if var calories = caloriesBurned {
calories.roundTo(places: 1)
print("\(calories) kcal") /// Prints "213.3 kcal"
}
复制代码
分离代码
当我们的类符合协议时,我们通常在同一个类中添加所有的协议方法。例如,我们会添加UICollectionViewDataSource
、UICollectionViewDelegate
和UICollectionViewDelegateFlowLayout
的所有方法。
我们可以使用扩展来分离每一个所需的方法。这使得代码更易读,更容易维护。
class ExampleViewController: UIViewController {
// Add the main code goes here
}
// MARK:- UICollectionViewDataSource
extension ExampleViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//
}
}
// MARK:- UICollectionViewDelegate
extension ExampleViewController: UICollectionViewDelegate {
//
}
// MARK:- UICollectionViewDelegateFlowLayout
extension ExampleViewController: UICollectionViewDelegateFlowLayout {
//
}
复制代码
我们的应用程序使用Google Sign-In作为主要的认证源,所以我们需要符合GIDSignInDelegate
,以接收成功登录后的更新。我们可以把这一点所需的代码分开–你猜对了–使用扩展。
import GoogleSignIn
class AuthenticationViewModel: NSObject, ObservableObject {
/// Main code goes here
}
// MARK:- GIDSignInDelegate
extension AuthenticationViewModel: GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if error == nil {
// Authentication successful
} else {
print(error.debugDescription)
}
}
}
复制代码
SwiftUI视图上的扩展
现在,让我们假设我们想添加一个自定义的大标题文本,就像苹果公司在其大多数应用程序中用于标题的文本。这个文本将表示某次锻炼的日期。我们也想在设置屏幕上使用确切的自定义文本。
为了在代码库中重复使用这段代码,我们将扩展Text
,添加一个largeTitle(:)
方法。
extension Text {
func largeTitle() -> some View {
self
.bold()
.foregroundColor(.primary)
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 37)
}
}
复制代码
现在我们可以在我们的视图上使用这个方法。
VStack {
Text("Settings").largeTitle()
}
复制代码
同样,假设我们想创建一个心形按钮来收藏一组锻炼项目。我们将创建一个ViewModifier
,在双击时切换心脏的颜色。
struct HeartButtonModifier: ViewModifier {
@Binding var state: Bool
func body(content: Content) -> some View {
content
.foregroundColor(state ? .red : .secondary)
.onTapGesture(count: 2) {
state.toggle()
}
}
}
复制代码
现在让我们在View
上创建一个extension
,这样我们就可以在我们的视图中使用它。
extension View {
func workoutLiked(state: Binding<Bool>) -> some View {
self.modifier(HeartButtonModifier(state: state))
}
}
复制代码
最后,我们将它作为一个修改器添加到Image
。
struct LikeView: View {
@State private var state = false
var body: some View {
Image(systemName: "heart.fill")
.workoutLiked(state: $state)
}
}
复制代码
为现有类型添加初始化器
我们可以使用一个extension
,为现有的类型添加一个新的自定义初始化器,接受不同的参数。
让我们假设你的设计者给你的颜色是十六进制的,而不是RGB值。利用之前给Color
添加计算类型属性的例子,我们将创建一个接受十六进制值的初始化器。如果我们想把RGB值做成整数的颜色,我们可以添加另一个初始化器。
extension Color {
init(hex: Int) {
let red = (hex >> 16) & 0xFF
let green = (hex >> 8) & 0xFF
let blue = hex & 0xFF
self.init(red: red, green: green, blue: blue)
}
init(red: Int, green: Int, blue: Int) {
let red = Double(red) / 255
let green = Double(green) / 255
let blue = Double(blue) / 255
self.init(red: red, green: green, blue: blue, opacity: 1.0)
}
}
复制代码
我们现在可以用它作为。
extension Color {
static var brand: Color {
Color(hex: 0x4B0082)
}
static var secondaryBrand: Color {
Color(red: 41, green: 0, blue: 71)
}
}
复制代码
结论
Swift中的扩展是为不属于自己的类型添加自己的功能的一种强大方式。这篇关于扩展的概述和这里的例子是为了帮助你理解扩展是如何工作的,以便你能在自己的Swift项目中实现和使用它们。
如果想进一步深入阅读,我推荐你阅读Swift文档中的以下文章。
The postSwift extensions:有例子的概述出现在LogRocket博客上。