上次找到一个iOS实战教程,用的是swift,看了下确实比obj-c要方便不少,于是看了《swift programming language》,总结下基础语法,swift版本为2.2。
1 数据类型
- 常量和变量: 用let声明常量,用var声明变量,常量只能赋值一次。
- 类型推断: 定义变量的时候可以不用声明类型,swift可以自动推断。不过要注意的是,如果初始值信息不够或者没有初始值,需要声明变量类型,见下面例子。
- 类型转换: 值不会隐式转换为其他类型,比如下面的字符串拼接,可以用
+
拼接字符串,但是整数需要先显示转换为String类型才可以拼接。另外,也可以通过反斜杠加括号的方式拼接。需要注意的是,不像python等其他语言,Swift的字符串必须用""
而不是''
括起来。 - 元组: 通过
()
创建,元组内部的元素数据类型可以任意,不需要一样。 - 数组和字典:数组和字典统一通过
[]
来创建。空的数组和字典需要使用初始化语法。如果类型信息可以推断出来,可以省掉类型信息。 - 可选类型: 可选类型用来处理值可能缺失的情况,这是swift独有的,C或者objective-C中都没有这个类型。定义的时候在类型后面加个
?
表示可选类型。注意,nil不能用于非可选的变量,如果变量有可能缺失值,则需要声明为可选类型。可选类型如果声明的时候没有赋值,则自动会被设置为nil。 - 类型别名: 可以通过typealias关键字来给已有类型定义一个别名。
//1 常量和变量
let apples = 3
apples = 4 //错误,常量只能赋值一次
var orange = 5
orange = 6 //正确
let orangesAreOrange = true
let turnipsAreDelicious = false
//2 类型推断
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70 //显示声明类型,因为根据初始值无法确定变量类型
//3 类型转换
let desc = "Apple num: "
let descLabel = desc + String(apples)
let appleSummary = "I have \(apples) apples."
//4 元组
let http404Error = (404, "Not Found") //元组里的数据类型可以任意,不需要一致
//5 数组和字典
var shoppingList = ["catfish", "water", "tulips"]
shoppingList[1] = "bottle of water"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
let emptyArray = [String]() //不加类型信息 let emptyArray = []
let emptyDictionary = [String: Float]() //不加类型信息 let emptyDictionary = [:]
//6 可选类型
var serverResponseCode: Int? = 404 //serverResponseCode 包含一个可选的 Int 值 404
serverResponseCode = nil //serverResponseCode 现在不包含值
oranges = nil //错误
var surveyAnswer: String?// surveyAnswer 被自动设置为 nil
//7 类型别名
typealias AudioSample = UInt16
var maxAmplitudeFound = AudioSample.min
2 控制流
与其他语言一样,有 if...else...
, while
, repeat...while
, for...in
。
- 括号问题: 循环或判断语句的括号可以省略,如下面的
for...in
,但是语句体的花括号{}
必须有。 - 强制解析和可选绑定: 在确定可选类型有值的情况下,使用
!
可以强制解析可选类型,也使用可选绑定来判断可选类型是否有值以及解析出可选类型的值。 - 隐式解析可选类型: 有些可选类型在第一次被赋值后可以确定总会有值,这时候可以将可选类型定义为隐式解析可选类型,隐式解析可选类型方式为将类型后面的
?
改为!
。 -
switch
和if
: switch语句支持任意类型的数据和各种操作,也不需要在每个case后面加break。还有if语句的判断必须是Bool类型,不能像其他语言那样可以直接拿整数值进行判断。
//1 括号问题
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)
//2 强制解析和可选绑定
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!).")
}
if let actualNumber = Int(possibleNumber) { //Int
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an integer")
}
// 输出 "'123' has an integer value of 123"
//3 可选类型/隐式解析可选类型
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要惊叹号来获取值
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // 不需要感叹号
//4 switch语句不用在每个case后面加break,if判断必须是Bool类型
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.")
}
let i = 1
if i {
//编译错误
}
if i == 1 {
//编译成功
}
3 函数
- 使用
func
来声明函数,使用->
来指定函数返回值的类型,函数可以带有可变个数的参数(可变参数后面带...
)。 - 函数可以嵌套函数。函数也可以作为参数和另一个函数的返回值。
//1 函数声明
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(42, 597, 12)
//2 函数作为参数
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, 17, 12]
hasAnyMatches(numbers, condition: lessThanTen)
4 对象和类 & 枚举和结构体
- 使用
class
来创建一个类,类中属性和常量声明普通变量和常量声明,只是它们属于这个类。引用实例变量用self
关键字,调用父类方法用super
关键字。属性也可以有getter
和setter
。 - 构造函数为
init
,析构函数为deinit
(注意后面没有括号),不需要func
关键字。 - 类之间继承用
:
,子类覆盖父类方法需要用override
关键字。 - 结构体和类相似,只是传参的时候结构体传的是值,类是传引用。
//1 类
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
deinit {
print("deinit")
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name) //调用父类的构造器方法
numberOfSides = 3 //修改父类定义的属性值
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral triagle with sides of length \(sideLength)."
}
}
let optionalSquare: EquilateralTriangle? = EquilateralTriangle(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength //处理可选变量的新语法,如果变量为nil,则返回nil,否则返回问号后面的值。注意,整个表达式返回的也是可选值。
//2 枚举和结构体
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
let hearts = Suit.Hearts
let heartsDescription = hearts.simpleDescription()
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
5 协议和扩展
- 使用
protocol
声明协议,extension
声明扩展。协议有点类似接口,而扩展用来为已有类添加新的功能。 - 类,结构体和枚举都可以实现协议。注意结构体中的方法需要声明为
mutating
,用于标记该方法会修改结构体。而类中的方法不需要,因为类中方法总是可以修改类属性。
//1 协议声明
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
//2 类实现协议
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
//3 结构体实现协议
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
//4 扩展Int,添加一个测试函数。
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
6 错误捕获
- 使用
throws
关键字声明一个函数可能抛出异常,使用do...catch
关键字捕获函数。
enum PrinterError: ErrorType {
case OutOfPaper
case NoToner
case OnFire
}
func sendToPrinter(printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.NoToner
}
return "Job sent"
}
do {
let printerResponse = try sendToPrinter("Bi Sheng")
print(printerResponse)
} catch {
print(error)
}
7 泛型
- 泛型用尖括号
<>
来标识,跟Java里面一样。
func repeatItem<Item>(item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
repeatItem("knock", numberOfTimes:4)