跳到主要内容

代码格式化规范

本文档概述了 SideStore 项目中 Swift 和 Objective-C 代码的格式化标准。一致的格式化能让代码库更易于阅读和维护。

通用原则

  • 一致性:遵循项目中已有的代码风格
  • 可读性:代码应易于阅读和理解
  • 简洁性:优先采用简单清晰的方案,而非取巧的做法
  • Apple 惯例:尽可能遵循 Apple 官方的 Swift 和 Objective-C 惯例

Swift 格式化

命名规范

变量与函数

  • 变量、函数和方法使用 camelCase
  • 使用能清晰表明用途的描述性名称
// ✅ Good
let downloadProgress: Float
func validateUserCredentials() -> Bool
var isAppInstalling: Bool

// ❌ Bad
let dp: Float
func validate() -> Bool
var installing: Bool

类、结构体、枚举与协议

  • 类型使用 PascalCase
  • 使用基于名词的描述性名称
// ✅ Good
class AppInstaller
struct InstallationProgress
enum AppState
protocol AppManaging

// ❌ Bad
class installer
struct progress
enum state
protocol managing

常量

  • 常量使用 camelCase
  • 可考虑对全局常量使用 SCREAMING_SNAKE_CASE
// ✅ Good
let maxRetryAttempts = 3
private let defaultTimeout: TimeInterval = 30.0

// Global constants
let MAX_CONCURRENT_DOWNLOADS = 5

// ❌ Bad
let MaxRetryAttempts = 3
let max_retry_attempts = 3

缩进与间距

缩进

  • 使用 4 个空格进行缩进(不要使用制表符)
  • 续行应与起始分隔符对齐
// ✅ Good
func installApp(withIdentifier identifier: String,
sourceURL: URL,
completion: @escaping (Result<Void, Error>) -> Void) {
// Implementation
}

// ❌ Bad
func installApp(withIdentifier identifier: String,
sourceURL: URL,
completion: @escaping (Result<Void, Error>) -> Void) {
// Implementation
}

行长

  • 尽可能将每行控制在 120 个字符以内
  • 在逻辑合理的位置断行
// ✅ Good
let longVariableName = SomeClass.createInstanceWithVeryLongMethodName(
parameter1: value1,
parameter2: value2
)

// ❌ Bad
let longVariableName = SomeClass.createInstanceWithVeryLongMethodName(parameter1: value1, parameter2: value2, parameter3: value3)

间距

  • 运算符两侧使用单个空格
  • 行尾不留多余空白
  • 在函数之间以及主要代码段之间使用一个空行分隔
// ✅ Good
let result = value1 + value2
if condition && anotherCondition {
// Code
}

func firstFunction() {
// Implementation
}

func secondFunction() {
// Implementation
}

// ❌ Bad
let result=value1+value2
if condition&&anotherCondition{
// Code
}
func firstFunction(){
// Implementation
}
func secondFunction(){
// Implementation
}

花括号与控制流

花括号风格

  • 左花括号与语句放在同一行
  • 右花括号单独成行,并与起始语句对齐
// ✅ Good
if condition {
doSomething()
} else {
doSomethingElse()
}

class MyClass {
func myMethod() {
// Implementation
}
}

// ❌ Bad
if condition
{
doSomething()
}
else
{
doSomethingElse()
}

Guard 语句

  • 使用 guard 语句进行提前返回
  • 保持 guard 条件简单易读
// ✅ Good
guard let url = URL(string: urlString) else {
completion(.failure(ValidationError.invalidURL))
return
}

guard !apps.isEmpty else {
return
}

// ❌ Bad
if let url = URL(string: urlString) {
// Long nested code block
} else {
completion(.failure(ValidationError.invalidURL))
return
}

类型标注与类型推断

何时使用类型标注

  • 当类型不明确时使用类型标注
  • 当 Swift 能明确推断出类型时,省略类型标注
// ✅ Good
let name = "SideStore" // Type is obvious
let timeout: TimeInterval = 30 // Type clarifies intent
var apps: [App] = [] // Empty array needs type annotation

// ❌ Bad
let name: String = "SideStore" // Redundant type annotation
let timeout = 30 // Unclear if Int or TimeInterval

函数声明

参数标签

  • 使用描述性的参数标签
  • 当省略第一个参数标签读起来更自然时,可以省略
// ✅ Good
func install(_ app: App, to device: Device)
func download(from url: URL, completion: @escaping (Data?) -> Void)

// ❌ Bad
func install(app: App, device: Device)
func download(url: URL, completion: @escaping (Data?) -> Void)

返回类型

  • 尽可能将返回类型放在同一行
  • 当签名过长时将返回类型换行
// ✅ Good
func processData() -> Result<ProcessedData, ProcessingError>

func complexFunction(withManyParameters param1: String,
param2: Int,
param3: Bool)
-> Result<ComplexReturnType, ComplexErrorType> {
// Implementation
}

Objective-C 格式化

命名规范

方法

  • 使用带有清晰参数标签的描述性方法名
  • 以小写字母开头
  • 使用 camelCase
// ✅ Good
- (void)installAppWithIdentifier:(NSString *)identifier
sourceURL:(NSURL *)sourceURL
completion:(void (^)(NSError *error))completion;

// ❌ Bad
- (void)install:(NSString *)id url:(NSURL *)url completion:(void (^)(NSError *))completion;

变量与属性

  • 使用 camelCase
  • Use descriptive names
  • 实例变量以下划线为前缀
// ✅ Good
@interface AppManager : NSObject
@property (nonatomic, strong) NSArray<App *> *installedApps;
@property (nonatomic, assign) BOOL isInstalling;
@end

@implementation AppManager {
NSURLSession *_networkSession;
dispatch_queue_t _processingQueue;
}

类与协议

  • Use PascalCase
  • 可考虑为公开类使用前缀(例如用 SS 表示 SideStore)
// ✅ Good
@interface SSAppInstaller : NSObject
@protocol SSAppManaging <NSObject>

// ❌ Bad
@interface appInstaller : NSObject
@protocol appManaging <NSObject>

间距与格式化

方法声明

  • 参数应垂直对齐
  • 使用一致的间距
// ✅ Good
- (instancetype)initWithIdentifier:(NSString *)identifier
title:(NSString *)title
version:(NSString *)version;

// ❌ Bad
- (instancetype)initWithIdentifier:(NSString *)identifier title:(NSString *)title version:(NSString *)version;

花括号

  • 左花括号放在同一行
  • 右花括号单独成行
// ✅ Good
if (condition) {
[self doSomething];
} else {
[self doSomethingElse];
}

// ❌ Bad
if (condition)
{
[self doSomething];
}
else
{
[self doSomethingElse];
}

注释与文档

Swift 文档

  • 使用 /// 编写文档注释
  • 为公开 API 包含参数和返回值的说明
/// Downloads and installs an app from the specified URL
/// - Parameters:
/// - identifier: The unique identifier for the app
/// - sourceURL: The URL to download the app from
/// - completion: Called when installation completes or fails
/// - Returns: A cancellable operation
func installApp(withIdentifier identifier: String,
sourceURL: URL,
completion: @escaping (Result<Void, Error>) -> Void) -> Operation {
// Implementation
}

Objective-C 文档

  • 使用 /** */ 编写文档注释
  • 遵循 HeaderDoc 或 Doxygen 约定
/**
* Downloads and installs an app from the specified URL
* @param identifier The unique identifier for the app
* @param sourceURL The URL to download the app from
* @param completion Block called when installation completes or fails
*/
- (void)installAppWithIdentifier:(NSString *)identifier
sourceURL:(NSURL *)sourceURL
completion:(void (^)(NSError *error))completion;

行内注释

  • 使用 // 编写单行注释
  • 保持注释简洁且有针对性
  • 解释为什么,而非是什么
// ✅ Good
// Retry failed downloads up to 3 times to handle temporary network issues
let maxRetryAttempts = 3

// ❌ Bad
// Set maxRetryAttempts to 3
let maxRetryAttempts = 3

错误处理

Swift 错误处理

  • 使用 Swift 原生的 throwsResult 类型进行错误处理
  • 创建有意义的错误类型
enum InstallationError: Error {
case invalidURL
case networkFailure(Error)
case insufficientStorage
case deviceNotSupported
}

func installApp() throws -> App {
guard let url = URL(string: urlString) else {
throw InstallationError.invalidURL
}
// Implementation
}

Objective-C 错误处理

  • 使用 NSError ** 参数模式
  • 在设置前,始终检查错误参数是否为非 nil
- (BOOL)installAppWithError:(NSError **)error {
if (someCondition) {
if (error) {
*error = [NSError errorWithDomain:SSErrorDomain
code:SSErrorCodeInvalidInput
userInfo:nil];
}
return NO;
}
return YES;
}

最佳实践

内存管理

  • 在 Swift 和 Objective-C 中正确使用 ARC
  • 注意循环引用;恰当使用 weakunowned 引用
// ✅ Good
class AppInstaller {
weak var delegate: AppInstallerDelegate?

private lazy var networkManager: NetworkManager = {
let manager = NetworkManager()
manager.delegate = self // Self is strong reference, but manager doesn't retain self
return manager
}()
}

线程

  • 始终在主队列上更新 UI
  • 为后台任务使用合适的队列
// ✅ Good
DispatchQueue.global(qos: .userInitiated).async {
let result = self.processData()
DispatchQueue.main.async {
self.updateUI(with: result)
}
}

可选值处理

  • 使用安全的解包技术
  • 优先使用 guard 语句进行提前返回
// ✅ Good
guard let data = response.data,
let apps = try? JSONDecoder().decode([App].self, from: data) else {
completion(.failure(ParsingError.invalidResponse))
return
}

工具与自动化

SwiftLint

可考虑使用 SwiftLint 自动强制执行其中的许多格式化规则:

# .swiftlint.yml
line_length: 120
function_body_length: 60
file_length: 400
type_body_length: 300

disabled_rules:
- trailing_whitespace

opt_in_rules:
- empty_count
- force_unwrapping

请记住:这些规范旨在提升代码的可读性和可维护性。如有疑问,应优先保证清晰性,并与现有代码库保持一致。