Skip to content

Swift 入门(22):模块导入与导出

如何导入系统框架、第三方库,以及如何设计自己的模块对外接口。

什么是模块(Module)

在 Swift 中,模块是代码分发的基本单位。每个模块都有自己的命名空间,可以包含类、结构体、协议、函数等。

常见的模块类型:

  • 系统框架FoundationUIKitSwiftUI
  • 第三方库:通过 CocoaPods、Swift Package Manager 安装的库
  • 自定义模块:你自己创建的 Swift Package 或 Framework

import 语法详解

1. 基础导入语法

swift
// 导入整个模块
import Foundation
import UIKit
import AuthenticationServices

// 导入后就可以使用模块中的公开类型
let date = Date()                    // Foundation.Date
let label = UILabel()               // UIKit.UILabel

2. 选择性导入

swift
// 只导入模块中的特定类型
import class UIKit.UIViewController
import struct Foundation.URL
import enum Foundation.ComparisonResult

// 导入特定函数
import func Darwin.sqrt

3. 重命名导入

swift
// 避免命名冲突
import UIKit
import class MyFramework.UIView as MyUIView

// 使用时区分
let systemView = UIView()    // UIKit.UIView
let customView = MyUIView()  // MyFramework.UIView

4. 测试专用导入

swift
// 仅在测试环境导入
#if DEBUG
import TestingFramework
#endif

@testable import MyApp  // 可以访问 internal 级别的内容

你提到的三个框架详解

Foundation

swift
import Foundation

// Foundation 提供基础数据类型和系统服务
let string = "Hello"
let date = Date()
let url = URL(string: "https://example.com")
let data = Data()
let userDefaults = UserDefaults.standard

常用场景:字符串处理、日期时间、网络请求、数据存储、JSON 解析

UIKit

swift
import UIKit

// UIKit 提供 iOS 用户界面组件
let viewController = UIViewController()
let label = UILabel()
let button = UIButton(type: .system)
let imageView = UIImageView()

常用场景:构建传统 iOS 界面、处理触摸事件、导航控制、动画

AuthenticationServices

swift
import AuthenticationServices

// 提供生物识别、Passkeys 等认证服务
let context = ASAuthorizationController()
let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: "example.com")

常用场景:Face ID/Touch ID 认证、Passkeys 登录、Safari 密码自动填充

模块的访问控制

访问级别从高到低

swift
// 1. open - 最开放,可被其他模块继承和重写
open class BaseViewController: UIViewController {
    open func setup() { }
}

// 2. public - 可被其他模块访问,但不能继承
public class APIClient {
    public func request() { }
}

// 3. internal - 模块内部可访问(默认级别)
internal class NetworkManager {
    func sendRequest() { }
}

// 4. fileprivate - 同一文件内可访问
fileprivate class FileHelper {
    func process() { }
}

// 5. private - 最严格,只有当前作用域可访问
private class Secret {
    private func encrypt() { }
}

如何设计可导出的模块

1. 创建 Swift Package

bash
# 创建新的 Swift Package
mkdir MyAwesomeKit
cd MyAwesomeKit
swift package init --type library

生成的 Package.swift

swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MyAwesomeKit",
    products: [
        .library(
            name: "MyAwesomeKit",
            targets: ["MyAwesomeKit"]),
    ],
    targets: [
        .target(
            name: "MyAwesomeKit",
            dependencies: []),
        .testTarget(
            name: "MyAwesomeKitTests",
            dependencies: ["MyAwesomeKit"]),
    ]
)

2. 设计公开 API

swift
// Sources/MyAwesomeKit/MyAwesomeKit.swift

import Foundation

// 对外暴露的主要接口
public class NetworkClient {
    public init() {}

    public func get(url: String) async throws -> Data {
        // 实现网络请求
        return Data()
    }
}

// 对外暴露的协议
public protocol DataProcessor {
    func process(_ data: Data) -> String
}

// 内部实现,不对外暴露
internal class InternalHelper {
    static func format(_ data: Data) -> String {
        return String(data: data, encoding: .utf8) ?? ""
    }
}

// 私有实现
private extension NetworkClient {
    func buildRequest(url: String) -> URLRequest? {
        guard let url = URL(string: url) else { return nil }
        return URLRequest(url: url)
    }
}

3. 使用你的模块

swift
// 在其他项目中使用
import MyAwesomeKit

class ViewController: UIViewController {
    let client = NetworkClient()

    override func viewDidLoad() {
        super.viewDidLoad()

        Task {
            do {
                let data = try await client.get(url: "https://api.example.com")
                print("获取到数据:\(data.count) bytes")
            } catch {
                print("请求失败:\(error)")
            }
        }
    }
}

实际开发中的最佳实践

1. 按功能模块化导入

swift
// 好的做法:按需导入
import Foundation          // 基础类型
import UIKit              // UI 组件
import AuthenticationServices  // 认证相关

class LoginViewController: UIViewController {
    // 使用各个模块的功能
}

2. 避免循环依赖

swift
// ❌ 避免这样的循环依赖
// ModuleA 导入 ModuleB
// ModuleB 导入 ModuleA

// ✅ 正确做法:提取公共协议到独立模块
// ModuleA 和 ModuleB 都依赖 CommonProtocols

3. 合理设计访问级别

swift
public class UserManager {
    // 对外接口
    public func login(username: String, password: String) async -> Bool {
        return await performLogin(username, password)
    }

    // 内部实现
    private func performLogin(_ username: String, _ password: String) async -> Bool {
        // 具体登录逻辑
        return true
    }

    // 内部状态
    private var isLoggedIn = false
}

常见问题与解决方案

问题 1:模块找不到

swift
// 错误信息:No such module 'SomeFramework'
// 解决方案:
// 1. 检查 import 语句拼写
// 2. 确认已在 Package.swift 或 Podfile 中添加依赖
// 3. 清理构建缓存:Product → Clean Build Folder

问题 2:访问级别错误

swift
// 错误信息:'SomeClass' is inaccessible due to 'internal' protection level
// 解决方案:确保要访问的类型标记为 public 或 open

// 模块内部
public class SomeClass {  // 添加 public 关键字
    public init() {}      // 构造函数也需要 public
}

问题 3:命名冲突

swift
// 两个模块都有同名类型
import ModuleA
import ModuleB

// 使用完整名称区分
let a = ModuleA.SomeClass()
let b = ModuleB.SomeClass()

// 或者使用重命名导入
import struct ModuleB.SomeClass as ModuleBClass

小结

这一篇我们学习了 Swift 的模块系统:

  • import 语法:基础导入、选择性导入、重命名导入
  • 系统框架:Foundation、UIKit、AuthenticationServices 的用途
  • 访问控制:open、public、internal、fileprivate、private 五个级别
  • 模块设计:如何创建可复用的 Swift Package
  • 最佳实践:避免循环依赖、合理设计 API、处理常见问题

下一篇我们将学习 Swift 的包管理器和依赖管理,让你能够更好地使用和分发 Swift 模块。

本站总访问