the swift programming language-Day1
0.前言
总是开新坑,总是不填坑。不过以前是兴趣,现在是工作需求,应该能有一点记录的。因为工作,开始了Mac APP开发,Objective-C还没上手,又要开始用Swift去做新项目。
不过自然不会去翻译书,只是记录一些遇到的有点新东西,顺便也方便以后的sharing。
1. 变量
1.1 var和let
在swift中,定义常数使用关键字let
,定义变量使用关键字let
.
在使用let
和 var
时,需要声明变量的类型,如果没有明确说明,编译器会根据实际值自行确定类型.e.g.1
2
3
4
5
6let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
var myVariable = 42
myVariable = 50//can be changed
swift is a type safe language.
2. 字符串 数组 集合 字典
可以使用String()进行强制类型转换,使用\()
把数据加入到字符串中.使用"""
定义多行数组
1
2
3
4
5
6
7
8
9let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
let quotation = """
I said "I have \(apples) apples."
And then I said "I have \(apples + oranges) pieces of fruit."
"""
swift中var声明的字符串是可变的,不同于OC中需要区分NSString与NSMutableString
字符串可使用+
,count,append
可以使用索引来访问和修改字符串,但不是传统数组的方式.
使用 startIndex
属性可以获取一个 String 的第一个 Character 的索引。使用 endIndex
属性可以获取最后一个 Character 的后一个位置的索引。因此,endIndex 属性不能作为一个字符串的有效下标。如果 String 是空串,startIndex
和 endIndex
是相等的。
通过调用 String 的 index(before:)
或 index(after:)
方法,可以立即得到前面或后面的一个索引。你还可以通过调用 index(_:offsetBy:)
方法来获取对应偏移量的索引,这种方式可以避免多次调用 index(before:)
或 index(after:)
方法。
e.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
14let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a
for index in greeting.indices {
print("\(greeting[index]) ", terminator: "")
}
子字符串重用原String的内存空间
数组与字典
可以使用
[]
来建立并访问数组和字典.e.g.1
2
3
4
5
6
7
8
9
10
11
12var shoppingList = ["catfish", "water", "tulips"]
shoppingList[1] = "bottle of water"
print(shoppingList)
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
var emptyArray = [String]()
var emptyDictionary = [String: Float]()
var letters = Set<Character>()数组通过下标访问修改变量,下标可以是一个范围.可以使用
+=
在末尾添加成员,可以使用append(_:)
在数组后面添加新的数据项.可以调用
insert(_:at:)
和remove(_:at_)
在某个索引位置添加删除成员(字符串也可以)如果我们同时需要每个数据项的值和索引值,可以使用 enumerated() 方法来进行数组遍历。e.g.
1
2
3
4
5
6
7
8for (index, value) in shoppingList.enumerated() {
print("Item \(String(index + 1)): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas集合可以做交集 并集 差集 是否为父子集等操作.
更新字典时使用方法
updateValue(_:forKey:)
时,将返回更新之前的值,这样可以检查更新是否成功.返回值是可选值类型.对某个键赋值
nil
可以移除该键,也可以使用removeValue(forKey:)
来移除.
3.Control Flow
3.1 条件语句
条件语句使用if
和switch
3.2 可选值(Optional Value)
在if语句中,可以将if
和var
结合起来处理可能缺省的变量.这样的变量就是可选值.可选值即可以是具体的值,也可以是nil
,在变量类型后添加?
来标记可选值.
e.g.1
2
3
4
5
6
7
8var optionalString: String? = "Hello"
print(optionalString == nil)
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
OC中,nil是个指向不存在对象的指针,所以只有对象才可以是nil,Swift中nil则是一个确定的值,当值缺省时就是nil.即使是基础类型,没值也是nil.为了使没有初始值的值可以被使用,便产生了Optional Value.
Optional Value本质上是一个枚举类型1
2
3
4
5
6
7
8
9
10
11
12
13
14enum Optional<T> : Reflectable, NilLiteralConvertible {
case None
case Some(T)
init()
init(_ some: T)
/// Haskell's fmap, which was mis-named
func map<U>(f: (T) -> U) -> U?
func getMirror() -> MirrorType
static func convertFromNilLiteral() -> T?
var number:Int? = 32
var number:Optioanl<Int>=32//相互等价
}
可以通过解包(unwrap)来获取Optional Value的实际状态.
显性解包
1)optional binds
if let
和if var
搭配在一起使用时,可以判断有值或是没值,可用于条件表达式.如2.2开头的例子中的if let name = optionalName
.2)通过
!
1
2
3
4var str:String? = "Hello World"
print(str) //{Some "Hello World"}
print(str!) //Hello World隐形解包
通过在声明时的数据类型后面加一个!
来实现:1
2var str:String! = "Hello World"
let implict :String = str可以通过Optional Chaining来安全地访问Optional的属性或者方法
当一个Optional值调用它的另一个Optional值的时候,Optional Chaining就形成了,基本上,Optional Chaining就是总是返回一个Optional的值,只要这个Chaining中有一个值为nil,整条Chaining就为nil.
Optional Chaining除了能将属性返回的类型变为Optional外,连方法的返回值都能强制变为Optional.
e.g.
1
2
3
4
5
6
7
8
9
10//不使用Optional Chaining需要判断两次
if let pet = jackon.pet {
if let toy = pet.favoriteToy {
toy.name
}
}
//使用Optional Chaining只需要判断一次
if let toy = jackon.pet?.favoriteToy {
toy.name
}
当Optional解包后的值为nil
时,可以通过??
来设置一个默认值
1 | let nickName: String? = nil |
3.3 switch-case
1 | let vegetable = "red pepper" |
执行完case之后,程序会退出,所以不需要break
case分支也可以是一个值的区间,可以是元组,元组可以用_来匹配所有可能的值,可以使用let对元组中的值进行值绑定
e.g.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
// 输出“(1, 1) is inside the box”
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
// 输出“on the x-axis with an x value of 2”
如果想像C中对case进行贯穿,需要显式调用 fallthrough
e.g.1
2
3
4
5
6
7
8
9
10
11let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// 输出“The number 5 is a prime number, and also an integer.”
3.4 循环
for-in循环,while循环以及repeat-while循环
1 | let interestingNumbers = [ |
在for-in循环中,可以使用<..
和...
来表示一个范围,前者右边为开区间,后者两边均为闭区间.
1 | var total = 0 |
使用stride(from:to:by)
在for-in中使用step
e.g.1
2
3
4let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
// 每5分钟渲染一个刻度线(0, 5, 10, 15 ... 45, 50, 55)
}
可以对循环体和条件语句使用标签,从而明确break
或continue
针对的具体代码块.
e.g.
1 | gameLoop: while square != finalSquare { |
像 if
语句一样,guard
的执行取决于一个表达式的布尔值。我们可以使用 guard
语句来要求条件必须为真时,以执行 guard
语句后的代码。不同于 if
语句,一个 guard
语句总是有一个 else
从句,如果条件不为真则执行 else
从句中的代码。
在 else 分支上的代码就会被执行。这个分支必须转移控制以退出 guard 语句出现的代码段。它可以用控制转移语句如 return、break、continue 或者 throw 做这件事,或者调用一个不返回的方法或函数,例如 fatalError()