swift设计原则
- Variables are always initialized before use.
- 变量使用之前必须已经被初始化。
- Array indices are checked for out-of-bounds errors.
- 数组下标被检查过,防止出现数组越界。
- Integers are checked for overflow.
- 数字会被检查过,防止出现数字溢出。
- Optionals ensure that nil values are handled explicitly.
- nil类型会被代码明确处理,使用Optionals封装,防止空指针异常。
- Memory is managed automatically.
- 内存自动管理。
- Error handling allows controlled recovery from unexpected failures.
- 错误处理允许恢复状态
swift优势
- 性能优化
- 强大的类型推断
- 语法简洁明确
特点
- 类型永远不会自动转换。例如 int 赋值给 float会编译不通过,而c语言可行。使用String()等
- 字符串支持插值(变量或者表达式)
- """多行字符串支持
- 集合类型,不管是array还是dictionary都使用中括号[]
- 创建空Array
let emptyArray = [String]() - swift中涉及到bool值的必须是bool类型,不能是对象和正整数。
- 如果某一个对象可能为空,我们应该使用Optionnal包装它。
- 支持元组,一般用于返回多个数据,而不需要返回array或者dic。
- 支持函数嵌套,函数中可以定义函数,与局部变量类似。
示例代码
1. if let用于接受可能为空的值或者??提供默认值
对一个非optional的值赋值为nil会编译失败
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
// 如果optionalName为nil,if条件不成立,将执行else
if let name = optionalName {
greeting = "Hello, \(name)"
} else {
}
也可以使用??为optional提供一个默认值
let fullName = "fullName"
greeting = "Hello, \(name ?? fullName)"
?进一步思考,如果我们的数据来源于网络或者其他地方,数据为空,会出现什么现象。
{ "status": 0, "data": null }json解析有两个用途,解析成map然后再赋值给model。 解析成map
在oc中,json中的null会被解析成NSNull对象,而不是nil。swift会将null解析成nil。
2. switch很全能
switch的条件可以直接作为参数,并且不需要写break。
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
3. for-in迭代器
在oc中也有for-in,但是oc中的for-in是无序的,而swift中的有序(对于array)。
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
}
}
}
print(largest)
4. range
var total = 0
for i in 0..<4 {
total += i
}
for i in 0...4 {
total += i
}
print(total)
5.函数
// 基本操作
func greet(person: String, day: String) -> String {
return "function"
}
greet(person: "John", day: "Wednesday")
// 隐藏调用时的参数名
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
// 闭包函数(闭包内作用域与闭包定义位置同级)
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
//闭包作为参数
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
// 匿名的闭包函数
numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
// 闭包函数省略参数类型和返回值类型,交给编译器。
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
类与对象
// 定义class方法(与其他语言基本相同)
// class可以不继承自任何对象,为基类。
// 属性必须有一个值,要么声明的时候设置,要么在init方法中设置。
// 子类覆盖父类方法必须使用override ,oc不需要。
class Shape {
var numberOfSides = 0
var name: String
var sideLength: Double
// 计算属性,一个值依赖于其他属性,以前一般使用方法来提供,swift中特意设置成计算属性。
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
init(name: String, sideLength: Double) {
self.name = name
self.sideLength = sideLength
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
// 使用class (与java等语言相同,与oc系列不同,oc必须先alloc再init)
// 这里调用默认构造函数即可,不需要调用alloc,也不需要使用new关键词。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
// 如果class中多个参数之前有需要关联的地方,使用willset和didset
// 如下,两个参数一个修改了,需要立刻修改另外一个,但是两个参数没有某一种直接的联系。
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
didSet {
print(666)
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name: name)
}
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
// Prints "10.0"
print(triangleAndSquare.triangle.sideLength)
// Prints "10.0"
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
// Prints "50.0"
optional values ?
// 可选值,也就是可能为nil的包装类型。
// 如果一个值可能为nil,在加上?以后,如果这个值为nil,?后面的将会忽略,表达式将直接返回nil
var op:String? //nil
op = nil //nil
op?.append("8") //nil
op = "String" //"String"
op?.append("9") //()
op //"String9"
// 我们也可以不用op?操作,这样,表达式的结果,就变成了一个optional类型。
enum struct
// struct是值类型,赋值的时候,会复制一份新的。
// swift中enum特性多很多
// enum的每个case的类型为enum,在oc中枚举类型的每个case值为数字。swift中为enum类型
enum Rank: Int {
case ace = 1
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
func simpleDescription() -> String {
//switch必须包含所有的case,或者提供一个default
switch self {
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
case .king:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
// switch不仅能存储固定的值。还能存储变量。
// 可以将其理解为,每个case能存储变量。
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
}
// Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."
protocol 与 extension
oc中也有协议和category,extension
swift中的extension与oc中基本一致
swift中protocol也可以定义变量
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
swift中enum和struct基本一致,他们和class一样可以实现protocol
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
// 结构体中方法声明mutating才能修改结构体其他属性,class不需要
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
// extension可以添加计算属性,和方法。还可以通过这个来实现protocol
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
错误处理
// 自定义错误,通过实现error
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
//throw抛出异常,方法立刻结束。用throws表明一个方法可以抛出异常
//异常如果没有被捕获,会导致程序crash
// 处理方法一 捕获错误
do {
let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
print(printerResponse)
} catch PrinterError.onFire {
print("I'll just put this over here, with the rest of the fire.")
} catch let printerError as PrinterError {
print("Printer error: \(printerError).")
} catch {
print(error)
}
// 处理方法二 try?
// 这种方式会忽略错误,表达式的值为nil
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
defer延迟执行
// 使用defer代码块,会在函数内等其他代码执行完,再最后执行defer代码块,在真正return之前(不是return语句)。
// 即使抛出异常,defer代码库还会执行,所以可以用来做一些清理。
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
fridgeContains("banana")
print(fridgeIsOpen)
// Prints "false"
泛型
// 泛型代表一种
// 通常来讲,泛型为类或者方法提供一个类型参数,以方便某个参数类型保持前后的一致性。
func makeArray<Item>(repeating item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
makeArray(repeating: "knock", numberOfTimes: 4)