Skip to content

Swift 入门(7):字符串与日期

字符串和日期是开发中最常用的数据类型。Swift 提供了强大且安全的操作方式。

字符串(String)

创建字符串

swift
let s1 = "Hello"
let s2 = String("World")

拼接

swift
let name = "Alice"
let greeting = "Hello, " + name
print(greeting)   // Hello, Alice

字符串插值

swift
let age = 20
print("My age is \(age)")   // My age is 20

遍历字符

swift
for ch in "Swift" {
    print(ch)
}

字符串长度

swift
let text = "Hello"
print(text.count)   // 5

子串

swift
let str = "Hello Swift"
let start = str.startIndex
let end = str.index(str.startIndex, offsetBy: 4)
let sub = str[start...end]
print(sub)   // Hello

常用方法

swift
let msg = " swift "
print(msg.uppercased())   // " SWIFT "
print(msg.lowercased())   // " swift "
print(msg.trimmingCharacters(in: .whitespaces))   // "swift"
print(msg.contains("sw")) // true

字符串替换与链式调用

replacingOccurrences 方法

swift
// 单个替换
let text = "Hello World"
let newText = text.replacingOccurrences(of: " ", with: "-")
print(newText)  // "Hello-World"

// 多个替换的链式调用
let original = "a+b/c=d"
let result = original
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")
print(result)  // "a-b_cd"

什么是 Data 类型?

Data 是 Swift Foundation 框架中的核心类型,用于表示二进制数据

swift
import Foundation  // Data 来自 Foundation 框架

// Data 的本质:字节数组
let data1 = Data([0x48, 0x65, 0x6C, 0x6C, 0x6F])  // "Hello" 的字节表示
print(data1)  // 5 bytes

// 常见的 Data 创建方式
let data2 = "Hello".data(using: .utf8)!        // 字符串 → Data
let data3 = Data(count: 10)                     // 创建 10 字节的空 Data
let data4 = Data(base64Encoded: "SGVsbG8=")!    // Base64 → Data

Data 的来源和用途

来源方法用途
字符串转换"text".data(using: .utf8)文本数据处理
网络请求URLSession 响应API 数据接收
文件读取Data(contentsOf: url)文件内容读取
图片处理UIImage.pngData()图片数据转换
JSON 序列化JSONSerialization.data()对象 → JSON 数据

实战:Base64URL 编码转换

swift
// 完整的 Data → Base64URL 流程
func dataToBase64URL(_ data: Data) -> String {
    // 1. Data → 标准 Base64 字符串
    var s = data.base64EncodedString()

    // 2. 标准 Base64 → Base64URL
    s = s.replacingOccurrences(of: "+", with: "-")
         .replacingOccurrences(of: "/", with: "_")
         .replacingOccurrences(of: "=", with: "")
    return s
}

// 使用示例
let textData = "Hello World".data(using: .utf8)!
let base64url = dataToBase64URL(textData)
print(base64url)  // "SGVsbG8gV29ybGQ"

// 更简洁的写法(一行完成)
return data.base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")

反向转换:Base64URL → Data

swift
// Base64URL 解码函数
func base64URLToData(_ s: String) -> Data {
    // 1. Base64URL → 标准 Base64
    var t = s.replacingOccurrences(of: "-", with: "+")  // - → +
             .replacingOccurrences(of: "_", with: "/")   // _ → /

    // 2. 计算并添加填充字符
    let pad = (4 - t.count % 4) % 4  // 计算需要多少个 = 填充
    if pad > 0 {
        t.append(String(repeating: "=", count: pad))  // 添加 = 填充
    }

    // 3. 标准 Base64 → Data
    return Data(base64Encoded: t) ?? Data()
}

数据转换过程详解

完整的双向转换流程:

swift
// 原始数据
let originalText = "Hello World!"
let originalData = originalText.data(using: .utf8)!
print("原始数据: \(originalText)")  // "Hello World!"

// 第一步:Data → Base64URL
let base64url = originalData.base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")
    .replacingOccurrences(of: "/", with: "_")
    .replacingOccurrences(of: "=", with: "")
print("Base64URL: \(base64url)")  // "SGVsbG8gV29ybGQh"

// 第二步:Base64URL → Data(你的代码)
let decodedData = base64URLToData(base64url)
let decodedText = String(data: decodedData, encoding: .utf8)!
print("解码结果: \(decodedText)")  // "Hello World!"

填充计算逻辑解析

Base64 编码要求长度是 4 的倍数,不足时用 = 填充:

swift
// 填充计算公式:(4 - length % 4) % 4
let examples = [
    ("SGVsbG8", 7),   // 7 % 4 = 3, 需要 1 个 =
    ("SGVsbG8g", 8),  // 8 % 4 = 0, 不需要填充
    ("SGVsbG8gV2", 10), // 10 % 4 = 2, 需要 2 个 =
]

for (base64url, length) in examples {
    let pad = (4 - length % 4) % 4
    let padded = pad > 0 ? base64url + String(repeating: "=", count: pad) : base64url
    print("\(base64url)\(padded) (添加 \(pad) 个 =)")
}

// 输出:
// SGVsbG8 → SGVsbG8= (添加 1 个 =)
// SGVsbG8g → SGVsbG8g (添加 0 个 =)
// SGVsbG8gV2 → SGVsbG8gV2== (添加 2 个 =)

实际应用:JWT Token 解析

swift
// JWT Token 通常使用 Base64URL 编码
func decodeJWTPayload(_ token: String) -> [String: Any]? {
    let parts = token.components(separatedBy: ".")
    guard parts.count == 3 else { return nil }

    // 解码 payload 部分(第二部分)
    let payloadData = base64URLToData(parts[1])

    // JSON 解析
    return try? JSONSerialization.jsonObject(with: payloadData) as? [String: Any]
}

// WebAuthn 挑战码解析
func decodeChallenge(_ challengeString: String) -> Data {
    return base64URLToData(challengeString)
}

Data 的常用方法

swift
let data = "Hello".data(using: .utf8)!

// 基本属性
print(data.count)        // 5 (字节数)
print(data.isEmpty)      // false

// 转换方法
let string = String(data: data, encoding: .utf8)  // Data → 字符串
let base64 = data.base64EncodedString()            // Data → Base64
let array = [UInt8](data)                          // Data → 字节数组

// 操作方法
var mutableData = data
mutableData.append("!".data(using: .utf8)!)       // 追加数据
print(String(data: mutableData, encoding: .utf8)!) // "Hello!"

方法解析表

方法作用示例
base64EncodedString()Data → Base64 字符串"SGVsbG8="
replacingOccurrences(of:with:)替换所有匹配的子串"a+b" → "a-b"
链式调用多个方法连续执行.method1().method2()

Base64 vs Base64URL 对比

swift
let data = "Hello World".data(using: .utf8)!

// 标准 Base64
let base64 = data.base64EncodedString()
print(base64)  // "SGVsbG8gV29ybGQ="

// Base64URL(URL 安全)
let base64url = data.base64EncodedString()
    .replacingOccurrences(of: "+", with: "-")  // + → -
    .replacingOccurrences(of: "/", with: "_")  // / → _
    .replacingOccurrences(of: "=", with: "")   // 移除填充
print(base64url)  // "SGVsbG8gV29ybGQ"

为什么需要 Base64URL?

swift
// ❌ 标准 Base64 在 URL 中会有问题
let url1 = "https://api.com/token=SGVsbG8+V29/bGQ="  // + 和 / 在 URL 中有特殊含义

// ✅ Base64URL 是 URL 安全的
let url2 = "https://api.com/token=SGVsbG8-V29_bGQ"   // - 和 _ 在 URL 中安全

实际应用场景

swift
// JWT Token 编码
func encodeJWTPayload(_ payload: [String: Any]) -> String {
    guard let data = try? JSONSerialization.data(withJSONObject: payload) else {
        return ""
    }
    return data.base64EncodedString()
        .replacingOccurrences(of: "+", with: "-")
        .replacingOccurrences(of: "/", with: "_")
        .replacingOccurrences(of: "=", with: "")
}

// WebAuthn 挑战码处理
func processChallenge(_ challengeData: Data) -> String {
    return challengeData.base64EncodedString()
        .replacingOccurrences(of: "+", with: "-")
        .replacingOccurrences(of: "/", with: "_")
        .trimmingCharacters(in: CharacterSet(charactersIn: "="))
}

日期(Date)

当前时间

swift
let now = Date()
print(now)   // 2025-09-14 12:34:56 +0000

日期格式化

swift
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let now = Date()
let str = formatter.string(from: now)
print(str)   // 2025-09-14 20:34:56

字符串转日期

swift
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"

if let date = formatter.date(from: "2025/09/14") {
    print(date)
}

日期计算

swift
let now = Date()
let tomorrow = now.addingTimeInterval(24 * 60 * 60)
print(tomorrow)

小结

  • 字符串:拼接 +,插值 \(var),常用方法 uppercasedcontainstrimmingCharacters
  • 日期Date() 获取当前时间,DateFormatter 用于格式化和解析。

本站总访问