Swift与Objective-C编程技巧及特性解析
1. Swift编程特性
1.1 替代类层次结构
在Swift中,可以使用带关联值的枚举来简化类层次结构。例如,用枚举表示不同度量系统下的距离:
enum Height {
case Imperial(feet: Int, Inches: Double)
case Metric(meters: Double)
case Other(String)
}
相比创建高度超类或协议以及每个度量系统的子类,枚举的解决方案更简单,且具有值类型的优势,代码也更紧凑易读。
再看一个更复杂的例子,创建一个健身应用来跟踪多种类型的锻炼:
enum Workout {
case ForTime(seconds: Int)
case ForReps(movements: [(name: String, reps: Int)])
}
创建锻炼时,只需定义与所需锻炼类型相关的值,无需使用类。
1.2 简洁表示状态
带关联值的枚举可用于表示事物的状态。最简单的例子是结果枚举,可包含值或错误描述:
enum NumberResult {
case Success(value: Int)
case Failure(reason: String)
}
func divide(first: Int, by second: Int) -> NumberResult {
guard second != 0 else {
return .Failure(reason: "Cannot divide by zero")
}
return .Success(value: first / second)
}
这是一种替代常规错误处理的方式,适用于将失败情况与成功情况同等对待的函数。
还可以用枚举表示随时间经历不同阶段的过程,即状态机。例如,下载过程的枚举:
enum DownloadState {
case Pending
case InProgress(percentComplete: Float)
case Complete(data: String)
}
下载进行中可获取完成百分比,完成后可获取下载的数据,且枚举能确保下载始终处于合理且明确定义的状态。
1.3 扩展系统类型以减少代码
Swift可以扩展现有类型。例如,在创建成绩跟踪程序时,常用浮点数表示百分比,但打印时格式可能不符合需求。可以通过扩展
Float
类型来解决:
extension Float {
var percentString: String {
return "\(self * 100)%"
}
}
let myPercent: Float = 0.32
print(myPercent.percentString) // 32.0%
这样可以使用自动补全来记住为浮点数定义的格式,且这些扩展可独立于其他程序特定代码,便于在新项目中复用。
不过,要注意避免创建过多扩展。对于更复杂的情况,使用组合模式可能更合适,例如定义一个
Percent
结构体:
struct Percent: CustomStringConvertible {
let value: Float
var description: String {
return "\(self.value * 100)%"
}
}
print(Percent(value: 0.3))
1.4 懒加载属性
1.4.1 避免不必要的内存使用
将属性标记为
lazy
,Swift会在首次访问时才初始化该属性。例如:
struct MyType {
lazy var largeString = "Some String"
}
let instance = MyType()
在上述代码中,
largeString
在访问前不会占用内存,适合可能并非每个实例都需要的大变量。
1.4.2 避免不必要的处理
可以使用闭包计算懒加载属性的值:
class Directory {
lazy var subFolders: [Directory] = {
var loaded = [Directory]()
// Load subfolders into 'loaded'
return loaded
}()
}
这里使用了自评估闭包,闭包会在首次访问
subFolders
属性时执行,避免了不必要的耗时操作。
1.4.3 逻辑本地化
与使用可选属性并在需要时赋值相比,懒加载属性将计算属性值的逻辑与属性定义放在一起,使代码更易读。
2. Objective-C基础
2.1 Swift与Objective-C的关系
Objective-C曾是苹果平台开发的主要语言,对Swift产生了很大影响。Swift设计为可与Objective-C互操作,Swift代码可调用Objective-C代码,反之亦然。苹果希望Swift更现代、交互性更强、安全、快速且强大,而Objective-C为其提供了比较基准。
2.2 Objective-C背景
Objective-C基于C语言,C是最早的高度可移植语言之一,可在不同处理器上运行。C是过程式编程语言,支持创建自定义类型,但没有内置的对象概念。Objective-C是C的面向对象扩展,添加了面向对象特性、新语法和内置库。苹果为Objective-C开发了Cocoa和Cocoa Touch API,这也是Objective-C对Swift开发者仍很重要的原因之一。
2.3 常量和变量
Objective-C的常量和变量与Swift类似,但声明和使用方式略有不同。以下是Swift和Objective-C声明变量的对比:
| 语言 | 变量声明 |
| ---- | ---- |
| Swift |
var number: Int
|
| Objective-C |
int number;
|
Objective-C中,变量类型在名称之前声明,且没有类型推断,每行代码必须以分号结尾。默认情况下,所有信息都被视为变量,要定义常量,需在类型前添加
const
关键字:
| 语言 | 常量声明 |
| ---- | ---- |
| Swift |
let number = 10
|
| Objective-C |
const int number = 10;
|
Objective-C也有值类型和引用类型,值类型在传递给其他函数时会被复制,同一实例不能有多个变量引用。而引用类型在Objective-C中通过添加星号
*
声明,所有引用类型都是可选的,指针可以指向
nil
,使用时需要解引用:
int *number = nil;
if (number == nil) {
// 处理指针为nil的情况
}
int actualNumber = *number;
Objective-C在指针引用类型方面不如Swift严格,例如可以创建一个指向与
int
指针相同值的
double
引用:
double *another = (double *)number;
最后,看一下Objective-C的
NSString
类型与Swift的
String
类型的对比:
| 语言 | 字符串声明 |
| ---- | ---- |
| Swift |
var myString = "Hello World!"
|
| Objective-C |
NSString *myString = @"Hello World!";
|
下面是一个简单的mermaid流程图,展示Objective-C变量声明的流程:
graph TD;
A[开始] --> B{变量或常量};
B -- 变量 --> C[声明类型 变量名;];
B -- 常量 --> D[const 声明类型 变量名 = 值;];
C --> E[结束];
D --> E;
3. 类型对比总结
3.1 值类型与引用类型对比
| 特性 | Swift | Objective-C |
|---|---|---|
| 声明方式 | 类型在变量名之后,有类型推断 | 类型在变量名之前,无类型推断 |
| 值类型 |
明确区分,如
Int
、
Float
等
|
类似,但判断更依赖是否有
*
|
| 引用类型 | 有明确的非可选和可选之分 | 所有引用类型都是可选,用指针表示 |
| 指针灵活性 | 避免了不安全的指针操作 | 指针类型不严格,可能导致类型错误 |
3.2 字符串类型对比
| 语言 | 字符串类型 | 声明示例 |
|---|---|---|
| Swift |
String
|
var myString = "Hello World!"
|
| Objective-C |
NSString
|
NSString *myString = @"Hello World!";
|
3.3 常量与变量声明对比
| 语言 | 变量声明 | 常量声明 |
|---|---|---|
| Swift |
var number: Int
|
let number = 10
|
| Objective-C |
int number;
|
const int number = 10;
|
下面是一个mermaid流程图,展示从Swift到Objective-C的类型转换思考流程:
graph LR;
A[Swift类型] --> B{值类型还是引用类型};
B -- 值类型 --> C[直接转换对应Objective-C值类型];
B -- 引用类型 --> D{是否可选};
D -- 非可选 --> E[转换为Objective-C指针类型并确保非nil];
D -- 可选 --> F[转换为Objective-C指针类型并处理nil情况];
C --> G[完成转换];
E --> G;
F --> G;
4. 综合应用建议
4.1 Swift编程建议
- 枚举使用 :在需要简化类型系统、表示状态或替代简单类层次结构时,优先考虑使用带关联值的枚举。例如在健身应用中跟踪不同类型的锻炼:
enum Workout {
case ForTime(seconds: Int)
case ForReps(movements: [(name: String, reps: Int)])
}
- 扩展使用 :合理使用系统类型扩展来减少代码重复,但要避免过度扩展。对于简单的格式化需求,如百分比输出,使用扩展是不错的选择:
extension Float {
var percentString: String {
return "\(self * 100)%"
}
}
- 懒加载属性使用 :当有大变量或耗时操作时,使用懒加载属性避免不必要的内存使用和处理。例如:
class Directory {
lazy var subFolders: [Directory] = {
var loaded = [Directory]()
// Load subfolders into 'loaded'
return loaded
}()
}
4.2 Objective-C编程建议
-
变量声明
:严格按照类型在前、变量名在后的方式声明变量,注意使用
const关键字声明常量。 -
指针使用
:在使用指针时,要时刻检查是否为
nil,避免出现空指针异常。例如:
int *number = nil;
if (number != nil) {
int actualNumber = *number;
}
- 与Swift交互 :在Swift项目中使用Objective-C代码时,要注意类型的转换和互操作性,确保代码的正确性。
4.3 跨语言开发建议
- 理解差异 :深入理解Swift和Objective-C在类型、语法、编程范式等方面的差异,以便在开发中做出正确的选择。
- 代码复用 :对于已有的Objective-C代码库,可以在Swift项目中合理复用,但要注意处理好类型转换和内存管理。
- 逐步迁移 :如果要将Objective-C项目迁移到Swift,可以逐步进行,先在Objective-C项目中引入Swift代码,再逐渐替换Objective-C代码。
下面是一个列表,总结跨语言开发的步骤:
1. 评估项目需求和已有代码库,确定哪些部分适合使用Swift,哪些部分可以继续使用Objective-C。
2. 在Swift项目中引入Objective-C代码,处理好桥接文件和类型转换。
3. 逐步将Objective-C代码替换为Swift代码,同时进行测试和调试。
4. 优化代码结构,提高代码的可读性和可维护性。
通过对Swift和Objective-C的特性分析和对比,我们可以更好地掌握这两种语言的编程技巧,在实际开发中做出更合适的选择,提高开发效率和代码质量。
超级会员免费看
2560

被折叠的 条评论
为什么被折叠?



