如何避免写垃圾代码:iOS开发篇

如何避免写垃圾代码:iOS开发篇

前言:从Linus的愤怒说起

"这简直是垃圾!这种东西根本不该发给我,尤其是在合并窗口的后期。像这个毫无意义的make_u32_from_two_u16()'辅助函数',它让这个世界变得更糟糕居住。"

Linus Torvalds对Meta工程师代码的激烈批评,虽然语气强硬,却指出了一个关键问题:不必要的抽象会增加认知负荷。在iOS开发中,我们同样面临这样的挑战------如何在追求代码复用和保持代码清晰度之间找到平衡。

认知负荷理论在iOS开发中的应用

什么是认知负荷?

认知负荷指的是人类大脑在处理信息时所需的心理资源总量。在编程中,它体现在:

  1. 内在认知负荷:问题本身固有的复杂度

  2. 外在认知负荷:代码表达方式带来的额外负担

  3. 关联认知负荷:用于构建心理模式的资源

swift 复制代码
// 高认知负荷示例:不必要的抽象

protocol DataProcessor {

func process(data: Data) -> ProcessedData

}

  


class ImageProcessor: DataProcessor {

func process(data: Data) -> ProcessedData {

// 复杂的处理逻辑

guard let image = UIImage(data: data) else {

throw ProcessingError.invalidData

}

// ...更多处理

return processedImage

}

}

  


// 使用时需要理解整个协议体系

let processor: DataProcessor = ImageProcessor()

let result = processor.process(data: imageData)
swift 复制代码
// 低认知负荷示例:直接明了的代码

func processImageData(_ data: Data) throws -> UIImage {

guard let image = UIImage(data: data) else {

throw ImageProcessingError.invalidData

}

// 清晰的图像处理逻辑

let scaledImage = image.resize(to: CGSize(width: 300, height: 300))

let filteredImage = scaledImage.applyFilter(.contrast(1.2))

return filteredImage

}

  


// 使用时一目了然

let processedImage = try processImageData(imageData)

iOS开发中常见的"垃圾代码"模式

1. 过度工程化的协议抽象

swift 复制代码
// ❌ 不良实践:过度抽象

protocol NetworkRequestable {

associatedtype Response: Decodable

var endpoint: String { get }

var method: HTTPMethod { get }

var parameters: [String: Any]? { get }

}

  


protocol JSONParsable {

associatedtype Model: Decodable

func parse(_ data: Data) throws -> Model

}

  


protocol Cacheable {

var cacheKey: String { get }

var cacheExpiry: TimeInterval { get }

}

  


struct UserProfileRequest: NetworkRequestable, JSONParsable, Cacheable {

typealias Response = UserProfile

typealias Model = UserProfile

let userId: String

var endpoint: String { "/users/\(userId)" }

var method: HTTPMethod { .get }

var parameters: [String: Any]? { nil }

var cacheKey: String { "user_profile_\(userId)" }

var cacheExpiry: TimeInterval { 3600 }

func parse(_ data: Data) throws -> UserProfile {

return try JSONDecoder().decode(UserProfile.self, from: data)

}

}

  


// ✅ 改进方案:适度的抽象

struct APIRequest {

let endpoint: String

let method: HTTPMethod

let parameters: [String: Any]?

let cacheKey: String?

let cacheExpiry: TimeInterval?

}

  


func fetchUserProfile(userId: String) async throws -> UserProfile {

let request = APIRequest(

endpoint: "/users/\(userId)",

method: .get,

parameters: nil,

cacheKey: "user_profile_\(userId)",

cacheExpiry: 3600

)

let data = try await NetworkManager.shared.execute(request)

return try JSONDecoder().decode(UserProfile.self, from: data)

}

2. 不必要的Helper函数泛滥

swift 复制代码
// ❌ 不良实践:无意义的helper函数

class UIHelper {

static func makeLabel(text: String,

fontSize: CGFloat,

textColor: UIColor) -> UILabel {

let label = UILabel()

label.text = text

label.font = UIFont.systemFont(ofSize: fontSize)

label.textColor = textColor

return label

}

static func makeButton(title: String,

backgroundColor: UIColor) -> UIButton {

let button = UIButton()

button.setTitle(title, for: .normal)

button.backgroundColor = backgroundColor

return button

}

}

  


// 使用这些"helper"反而增加了理解成本

let titleLabel = UIHelper.makeLabel(text: "欢迎",

fontSize: 16,

textColor: .black)

let actionButton = UIHelper.makeButton(title: "确定",

backgroundColor: .blue)

  


// ✅ 改进方案:直接创建或者使用合理的扩展

extension UILabel {

convenience init(text: String,

fontSize: CGFloat,

color: UIColor = .black) {

self.init()

self.text = text

self.font = UIFont.systemFont(ofSize: fontSize)

self.textColor = color

}

}

  


// 使用更清晰明了

let titleLabel = UILabel(text: "欢迎", fontSize: 16)

let actionButton = UIButton(type: .system).then {

$0.setTitle("确定", for: .normal)

$0.backgroundColor = .blue

}

3. 复杂的闭包和函数式编程滥用

swift 复制代码
// ❌ 不良实践:过度复杂的函数式链式调用

let processedItems = items

.filter { $0.isActive }

.map { item in

return item.transformed { value in

return value * coefficientCalculator(

base: baseValue,

modifier: environmentalModifier

)

}

}

.compactMap { $0.finalize() }

.sorted { $0.priority > $1.priority }

.flatMap { $0.components }

  


// ✅ 改进方案:分解为清晰的步骤

var activeItems = items.filter { $0.isActive }

  


var transformedItems: [ProcessedItem] = []

for item in activeItems {

let coefficient = calculateCoefficient(

base: baseValue,

modifier: environmentalModifier

)

let transformed = transformItem(item, coefficient: coefficient)

if let finalized = transformed.finalize() {

transformedItems.append(finalized)

}

}

  


let sortedItems = transformedItems.sorted { $0.priority > $1.priority }

let result = sortedItems.flatMap { $0.components }

iOS特定场景的认知负荷优化

1. UIKit vs SwiftUI的认知负荷考量

swift 复制代码
// UIKit示例:传统的MVC模式

class UserProfileViewController: UIViewController {

var user: User?

private let nameLabel = UILabel()

private let emailLabel = UILabel()

private let avatarImageView = UIImageView()

override func viewDidLoad() {

super.viewDidLoad()

setupUI()

configureWithUser()

}

private func setupUI() {

// 大量的布局代码...

nameLabel.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(nameLabel)

NSLayoutConstraint.activate([

nameLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),

nameLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),

nameLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16)

])

// 更多UI设置代码...

}

private func configureWithUser() {

nameLabel.text = user?.name

emailLabel.text = user?.email

// 图片加载等...

}

}

  


// SwiftUI示例:声明式UI降低认知负荷

struct UserProfileView: View {

let user: User?

var body: some View {

VStack(alignment: .leading, spacing: 16) {

HStack {

AsyncImage(url: user?.avatarURL) { image in

image.resizable()

} placeholder: {

Color.gray

}

.frame(width: 60, height: 60)

.clipShape(Circle())

VStack(alignment: .leading) {

Text(user?.name ?? "")

.font(.headline)

Text(user?.email ?? "")

.font(.subheadline)

.foregroundColor(.secondary)

}

}

.padding()

}

}

}

2. 内存管理中的认知负荷陷阱

swift 复制代码
// ❌ 不良实践:复杂的内存管理

class DataManager {

static let shared = DataManager()

private var cache: [String: Any] = [:]

private var observers: [NSObjectProtocol] = []

func fetchData(for key: String,

completion: @escaping (Result<Data, Error>) -> Void) {

if let cached = cache[key] as? Data {

completion(.success(cached))

return

}

// 复杂的网络请求和缓存逻辑

let request = URLRequest(url: URL(string: key)

let task = URLSession.shared.dataTask(with: request) { [weak self] data, _, error in

guard let self = self else { return }

if let error = error {

completion(.failure(error))

return

}

guard let data = data else {

completion(.failure(NSError(domain: "NoData", code: -1)))

return

}

self.cache[key] = data

completion(.success(data))

// 通知观察者

self.notifyObservers(for: key, data: data)

}

task.resume()

}

private func notifyObservers(for key: String, data: Data) {

// 复杂的观察者通知逻辑

}

}

  


// ✅ 改进方案:使用现代并发框架简化内存管理

actor DataCache {

private var storage: [String: Data] = [:]

func data(for key: String) async throws -> Data {

if let cached = storage[key] {

return cached

}

let data = try await downloadData(from: key)

storage[key] = data

return data

}

private func downloadData(from key: String) async throws -> Data {

let url = URL(string: key)!

let (data, _) = try await URLSession.shared.data(from: url)

return data

}

}

  


// 使用示例清晰简单

let data = try await DataCache().data(for: "https://example.com/data")

AI时代的iOS代码编写策略

1. 为AI助手优化的代码结构

swift 复制代码
// 🤖 AI友好的代码结构

struct UserProfileConfig {

let userId: String

let shouldLoadAvatar: Bool

let cachePolicy: CachePolicy

let timeout: TimeInterval

}

  


// 清晰的函数签名和职责分离

func loadUserProfile(config: UserProfileConfig) async throws -> UserProfile {

// 1. 检查缓存

if let cached = try await checkCache(for: config.userId, policy: config.cachePolicy) {

return cached

}

// 2. 网络请求

let userData = try await fetchUserData(

userId: config.userId,

timeout: config.timeout

)

// 3. 数据处理

let profile = try processUserData(

userData,

loadAvatar: config.shouldLoadAvatar

)

// 4. 缓存结果

try await cacheProfile(profile, for: config.userId)

return profile

}

  


// 每个辅助函数都有明确的单一职责

private func checkCache(for userId: String, policy: CachePolicy) async throws -> UserProfile? {

// 清晰的缓存检查逻辑

}

  


private func fetchUserData(userId: String, timeout: TimeInterval) async throws -> Data {

// 清晰的网络请求逻辑

}

  


private func processUserData(_ data: Data, loadAvatar: Bool) throws -> UserProfile {

// 清晰的数据处理逻辑

}

2. 测试中的认知负荷考虑

swift 复制代码
// ❌ 测试代码中的高认知负荷

func testUserProfileLoading() {

let mockNetwork = MockNetworkService()

let mockCache = MockCacheService()

let mockParser = MockDataParser()

let config = AppConfig.shared

let manager = UserProfileManager(

network: mockNetwork,

cache: mockCache,

parser: mockParser,

config: config

)

mockNetwork.stubResponse = .success(testData)

mockCache.stubResult = .empty

mockParser.stubResult = testUser

let expectation = self.expectation(description: "Profile loaded")

manager.loadProfile(userId: "123") { result in

switch result {

case .success(let user):

XCTAssertEqual(user.name, "Test User")

case .failure:

XCTFail("Should not fail")

}

expectation.fulfill()

}

waitForExpectations(timeout: 1)

}

  


// ✅ 低认知负荷的测试代码

func testUserProfileLoading() async throws {

// 设置清晰的测试数据

let testUser = User.testInstance()

let testData = try JSONEncoder().encode(testUser)

// 使用简单的测试依赖

let service = UserProfileService(

network: .mock(returning: testData),

cache: .empty,

parser: .standard

)

// 清晰的测试逻辑

let result = try await service.loadProfile(userId: "123")

// 明确的断言

XCTAssertEqual(result, testUser)

}

  


// 测试辅助扩展

extension User {

static func testInstance() -> User {

User(

id: "123",

name: "Test User",

email: "test@example.com"

)

}

}

  


extension NetworkService {

static func mock(returning data: Data) -> Self {

// 简单的mock实现

}

}

实用工具和技巧

1. Xcode功能优化认知负荷

swift 复制代码
// 使用// MARK: 注释组织代码

class UserProfileViewController: UIViewController {

// MARK: - Properties

private var user: User?

private var isLoading = false

// MARK: - UI Components

private let nameLabel = UILabel()

private let avatarImageView = UIImageView()

// MARK: - Lifecycle

override func viewDidLoad() {

super.viewDidLoad()

setupUI()

loadData()

}

// MARK: - Setup

private func setupUI() {

configureLabel()

configureImageView()

setupConstraints()

}

// MARK: - Data Loading

private func loadData() {

guard !isLoading else { return }

isLoading = true

Task {

await fetchUserProfile()

}

}

// MARK: - Helper Methods

private func configureLabel() {

nameLabel.font = .preferredFont(forTextStyle: .headline)

nameLabel.textColor = .label

}

}

2. 代码审查清单

graph TD A[代码审查开始] --> B{是否有不必要的抽象?} B -->|是| C[考虑内联或简化] B -->|否| D{单个函数是否超过50行?} C --> E[重构完成] D -->|是| F[考虑分解函数] D -->|否| G{命名是否清晰明确?} F --> E G -->|否| H[改进命名] G -->|是| I{认知负荷是否最低?} H --> E I -->|否| J[优化代码结构] I -->|是| K[批准代码] J --> E K --> E

总结:编写高质量iOS代码的核心原则

在iOS开发中,始终将降低认知负荷作为首要目标。这意味着:

  1. 避免过早优化:不要为了抽象的"完美架构"而增加理解难度

  2. 保持代码局部性:相关代码应该放在一起,减少文件跳转

  3. 适度重复优于错误抽象:有时候重复的代码比错误的抽象更可取

🔧 工具使用

  1. 利用Xcode功能 :合理使用// MARK:、代码折叠、快速帮助等功能

  2. 拥抱现代并发 :使用async/await简化异步代码

  3. 编写AI友好代码:为代码助手提供清晰的上下文

原文:xuanhu.info/projects/it...

相关推荐
HarderCoder2 小时前
Swift 语法速通:iOS 开发必会的 8 大核心概念(图解+类比)
swift
HarderCoder3 小时前
Swift 6 并发编程:深入理解 `@unchecked Sendable` 的合法使用与陷阱
swift
HarderCoder3 小时前
Swift 6.0 协议扩展:解锁协议新特性,写出更优雅、更高效的代码
swift
HarderCoder16 小时前
iOS 知识积累第一弹:从 struct 到 APP 生命周期的全景复盘
ios
叽哥1 天前
Flutter Riverpod上手指南
android·flutter·ios
HarderCoder2 天前
Swift 6 并发时代,如何优雅地“抢救”你的单例?
swift
zhangmeng2 天前
FlutterBoost在iOS26真机运行崩溃问题
flutter·app·swift
HarderCoder2 天前
SwiftUI 踩坑记:onAppear / task 不回调?90% 撞上了“空壳视图”!
swift
HarderCoder2 天前
@isolated(any) 深度解析:Swift 并发中的“隔离追踪器”
swift