- swift中的代码是在全局作用域下,这些代码直接作为整个项目的入口,所以这里并不需要main函数。(Swift没有main函数,从top level code的上方开始往下执行(就是第一个非声明语句开始执行[表达式或者控制结构,类、结构体、枚举和方法等属于声明语句]),不能存在多个top level code文件(否则编译器无法确定执行入口,事实上swift隐含一个main函数,这个main函数会设置并调用全局 “C_ARGC C_ARGV”并调用由top level code构成的top_level_code()函数);)
- Swift通过import引入其他类库(和Java比较像);
- Swift语句不需要双引号结尾(尽管加上也不报错),除非一行包含多条语句(和Python有点类似);
print("Hello, world!")
常量与变量
- 使用let声明一个常量,使用var声明一个变量。常量的值在编译阶段并不需要被编译器所知道,但常量在最初定义时必须赋值。
var myVariable = 42
myVariable = 50
let myConstant = 42
- 你可以为变量或常量指定你所所想的类型。然而你不不需要每次都这么做。当你定义了一个变量或常量时,编译器可以推测这个变量或常量的类型。
let implicitInteger = 70
let implicitDouble = 70.0
- 例如上面两行,编译器会将implicitInteger的类型视为整型,因为这个常量最初的值为一个整数。
- 当然也可以显示说明变量或常量的类型。形式如下:
let explicitDouble: Double = 70
练习:
let explicitDouble: Double = 70
let explicitFloat:Float=4
let implicitInteger = 70
print("explicitDouble=",explicitDouble);
print("explicitFloat=",explicitFloat);
print("implicitInteger=",implicitInteger);
运行结果:
- 一个值不会随意改变类型,如果你需要改变一个值得类型,需要强制类型转换。举例说明:
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
- 有一种更加简单的方法将其它类型转换成字符串类型。那就是使用\()。
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
- 通过[ ]符号创建数组。在swift中,既可以通过数组下标访问数组元素,也可以通过关键字访问数组元素。
- 例子:
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
var occupations = [
"Malcolm": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
for item1 in shoppingList{
print(item1)
}
for item2 in occupations{
print(item2)
}
- 创建一个空数组:
let emptyArray = [String]()
- 创建一个空的字典:
let emptyDictionary = [String: Float]()
- 如果数组或者字典的类型可以被推测,可以用如下表达式:
shoppingList = []
occupations = [:]
控制流
- if 和 switch都可以用来做条件判断,for-in,for,while,repeat-while都可以用来做循环。swift中条件语句的判断语句的括号和循环语句的括号是可以省略的,而它们之后的{ }是不能省略的。
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
print(teamScore)
- if和let一起用可能导致值丢失,所以必须把这些量定义为可选值(optional)。
- 通过在类型后面加一个 ? 来将变量声明为 Optional 的。如果不是 Optional
的变量,那么它就必须有值。如果可能没有值的话,我们使用 Optional 并且将它设置为 nil 来表示没有值。 - 如果可选值为nil,则条件判断为false,花括号中的代码会被跳过。反之,可选值去包装并且赋给let后面的常量,使得去包装的值可以在代码块内部访问。
var optionalString: String? = "Hello"
var notoptionalString: String?
print(optionalString == nil)
print(notoptionalString == nil)
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}
print(greeting)
var optionalname: String?
var smiling = "Hey!"
if let name = optionalname {
smiling = "Hello, \(name)"
}
print(smiling)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
参考:Swift 可选值(Optional Values)介绍
- 也可以使用??操作符来处理可选值。
let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickName ?? fullName)"
print(informalGreeting)
- 在swift中,switch支持任意类型的数据和多种比较,不再局限于整数或者只是比较像等。
参考:Swift Switch介绍
- 在 for-in中通过提供一对关键字-值实现对字典的迭代。字典是一个无序的集合,所以他们的键和值在一个任意的顺序迭代。
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)
- while和do while的用法:
var n = 2
while n < 100 {
n = n * 2
}
print(n)
var m = 2
repeat {
m = m * 2
} while m < 100
print(m)
- 可以通过使用..<来控制循环变量的值,间接限制循环的次数,不是直接限制循环的次数。
var total = 0
for i in 0..<4 {
total += i
}
print(total)
运行结果为6。
函数和闭包
- 使用func 声明一个函数。通过函数名称和参数调用一个函数。使用->区分参数名和函数返回的类型。
-
在Swift的历史版本中出现过在调用函数时不需要指定任何函数参数(或者从第二个参数开始指定参数名),在调用方法时则必须从第二个参数开始必须指定参数名等多种情况,而在Swift3.0中不管是函数还是方法都必须从第一个参数开始必须指定参数名(当然可以使用“_”明确指出调用时省略参数)。
swift3.0的表示法:
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
由于用的在线编译器不支持swift3.0,所以我用以前的语法跑了一遍。
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
print(greet("Bob", day: "Tuesday"))
- 使用元组可以返回多个值,元组中的元素既可以通过下标访问,也可以通过名字访问。
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum)
print(statistics.2)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 函数也可以有可变数量的参数,将这个参数看成是一个数组。
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(numbers: 42, 597, 12)
- 函数可以嵌套。嵌套的函数可以访问在外层函数定义的变量。使用嵌套函数可以组织更长更复杂的函数。
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
- 函数是一个引用类型,就是说一个函数可以返回另一个函数作为返回值。类似于C语言中的指针函数。
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
注意:上面的例子(Int) -> Int 表示返回函数的参数类型和返回类型。
- 一个函数可以使用一个函数作为它的的返回值。
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)
- Swift中的闭包其实就是一个函数代码块,它和ObjC中的Block及C#、Java中的lambda是类似的。闭包的特点就是可以捕获和存储上下文中的常量或者变量的引用,即使这些常量或者变量在原作用域已经被销毁了在代码块中仍然可以使用。事实上前面的全局函数和嵌套函数也是一种闭包,对于全局函数它不会捕获任何常量或者变量,而对于嵌套函数则可以捕获其所在函数的常量或者变量。通常我们说的闭包更多的指的是闭包表达式,也就是没有函数名称的代码块,因此也称为匿名闭包。
- 函数实际上是一种特殊的闭包。在闭包体内使用in去分离参数和返回值。
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
- 你已经有几种方式可以更自如的写闭包。当一个闭包类型已经知道,比如是一个代理的回调,你可以去除参数类型、返回类型或者两个都去除。单个语句闭包会把它语句的值当做结果返回。
let mappedNumbers = numbers.map({ number in 3 * number })
print(mappedNumbers)
- 你可以通过参数位置访问-这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。当一个闭包是传给函数的唯一参数,你可以完全忽略括号。
let sortedNumbers = numbers.sorted { $0 > $1 }
print(sortedNumbers)
对象和类
- 用class关键字,后面加上一个类名来创建一个类。类中属性的定义和普通常量或者变量的定义相同,但属性是属于这个类的。类中方法和函数的定义和普通方法与函数的定义相同。
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
- 通过在类名后面加括号来创建类的一个实例。一个实例通过一个小圆点来访问这个类的属性和方法。
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
- 上面版本的shape类少了一些重要的东西:在一个实例被创建时缺少初始化程序来初始化这个类。可以使用init来初始化一个类。
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
-
注意怎样用self来区分属性和初始化程序的参数。当你创建一个类的实例时,初始化程序的参数就像函数调用那样传递。每一个属性都需要给它分配一个值,要么是在属性定义的时候,那么是在初始化程序时。
-
在一个对象(实例)被销毁或者重新分配之前。使用deinit做一些清理工作。
-
子类要继承父类是通过在子类名后面加上冒号,然后跟上父类名。没有要求一个类必须继承一个标准的根类,所以你可以根据需要继承一个父类。
-
子类可以重写父类声明的方法,即在方法前加上 override,如果没有加override就重写的话会报错。编译器也会检查有override的方法在父类中存不存在。
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 除了存储属性,属性可以有getter和setter,称为计算属性。
参考:getter 和 setter
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 triangle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
triangle.perimeter = 9.9
print(triangle.sideLength)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
-
在perimeter的setter中,参数被隐含地命名为newValue。你也可以将参数名字在set后面用括号括起来。
-
注意EquilateralTriangle类的构造器有三个不同的步骤:
给子类的属性赋值。
调用父类的构造器。
改变定义在父类中的属性的值。任何其它的使用方法,getter,setter的步骤可以在这一步完成。
-
如果你不需要一个计算属性但是仍然想在代码运行前后设定新值的话,可以使用willSet和DidSet。
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
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)
print(triangleAndSquare.triangle.sideLength)
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 当处理可选类型,你可以在方法属性和subscripting
前面加上问号?。如果?号前面的值是nil,那么问号后面的所有值都是nil.否则,?之后的所有代码都会运行。在这两种情况下,整个表达式的值是可选类型的。
swift3.0-将元组加到数组中
var student1 = (number:"2014110323",name:"allen",age:20,sex:"f");
var student2 = ("2014110324","iverson",21,"m");
print("\(student1.number) \(student1.name) \(student1.age) \(student1.sex)")
print("\(student2.0) \(student2.1) \(student2.2) \(student2.3)");
var (number,name,age,sex) = student2;
print("\(number)")
var student3 = student2;
let (number1,_,age1,sex1) = student3
print("\(student3.0) \(student3.1) \(student3.2) \(student3.3)");
print("\(number1) \(age1) \(sex1)")
student1.number = "001"
student2.0 = "002"
student3.0 = "003"
var Student:[(String,String,Int,String)] = []
Student.append(student1);
Student.append(student2);
Student.append(student3);
for var student in Student{
print(student)
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
swift-数组,元组,字典优缺点
字典
优点:
通过key值进行索引,查找效率高
通过key值进行数据标注,可读性高,易于区分多种数据
key值唯一,增删改可以保证数据唯一性
缺点:
一个value必须对应一个key,尽管有时不需要key
key值顺序不定,字典对key值表进行了hash,所以不方便存储对顺序敏感的数据
数组
优点:
数据存储顺序固定,增删改也通过index来进行
集成了遍历方法,适合对大量同类数据的处理
不需要定义key,写法相对简单
缺点:
访问特定数据时,查找效率不高
处理特定数据时,需要牢记数据的index,可读性不好,容易产生错位处理
元组
优点:
元组可以同时存储多种类型元素,且元素类型固定,以保证数据安全,除非你定义数据类型为Any。编译器会对赋值参数类型进行检查
元组的元素个数固定,不允许增加、删除,编译器会严格校验赋值参数个数
无需定义key,但是必要时可以为数据命名,方便数据访问
适合同时遍历多元数据,例如官方文档的例子
for (index, value) in shoppingList.enumerate()
缺点:
不适合存储大量数据,因为元组不支持append、remove等方法
考虑到工程实际情况,后端使用的语言可能不支持元组,需要转换为其他格式
转自swift3.0快速入门