Cowboy Tech

Swift语言基础

常量和变量

let设定常量

let encouragement = "You can do it!"

即使两个常量相同,也不能互相赋值

//: ### Two ways of being immutable - #1 Assignment
var goat = UIImage(named:"Chinese-New-Year-3.jpg")!
let yearsOfTheGoat = [1967, 1979, 1991, 2003, 2015]
let yearsOfTheSheep = [1967, 1979, 1991, 2003, 2015]

//以下结果会报错
yearsOfTheGoat = yearsOfTheSheep

常量不能有更改

//以下结果会报错
yearsOfTheGoat.append(2027)

var设定变量

var personalizedEncouragement = "You can do it, Lauren!"
personalizedEncouragement = personalizedEncouragement.stringByReplacingOccurrencesOfString("Lauren", withString: "Cameron")  

var + 变量名 : 类型

var age: Int  
var string: String = "smile"  

省略类型由系统来推断

var a = 20, b:String, c = "Swift"  

标识符必须以字符(包括Unicode字符),下划线_,美元符$开头,但不能以数字开头,不可以包含空格,不能使用关键字,其长度没有限制

数据类型

整型

用Int就可以了。其实还有Int16,Int32

let oneMillion = 1_000_000 //可以增加下划线作为分隔符
print(oneMillion)

整型之间转换必须是显式转换

var book1: Int16 = 100
var book2: Int32 = 30
var totalPrice = Int32(book1) + book2 //必须先转换,否则会报错

正无穷,负无穷,非数

var w = 4.0 / 0.0   //正无穷
var w = - 4.0 / 0.0 //负无穷
var f = 0.0 / 0.0   //非数

浮点运算

var width: Float = 2.1
var height: Double = 3.9
var area1 = width * Float(height) //必须先转换,否则会报错

//在Swift2.0 版本中貌似整数不转换也可以哦
var area2 = Int(width) * 4 //必须先转换,否则会报错

类型别名

typealias Age = UInt16
let myAge:Age = 10

元组

赋值方式1.直接赋值

var score = (140,140,"Good")

赋值方式2.先申明类型

var health : (Int , Int , String)
health = (182 , 78 , "Good")

print ("health元组的值为:\(health)")  //打印元组所有
print ("health元组中身高的值为:\(health.1)") //打印元组中第二个值

赋值方式3.key-value赋值

//顺序可以调换
var score2 = (math:140, English:140, Assessment:"A")
var score3 :(math:Int, English:Int, Assessment:String)
score3 = (English:140, math:145, Assessment:"A")
print("score3 中数学的成绩是: \(score3.math)")

元组中的嵌套

var test:(Int,(Int,String))
test = (10,(100,"Swift"))
print("test元组中第二个元素的第一个元素为:\(test.1.0)")

可选类型

在swift中不能赋值nil给变量或者对象

var x: Int
x = nil //这样赋值必报错

var c: AnyObject
c = UIColor.redColor()
c = nil //这样赋值必报错

如果遇到可能会出现nil的情况,就使用可选类型,在变量后添加?

情况1. 可能返回值为nil

var y: Int?
var s1: String
var s2: String

s1 = "123"
s2 = "ABC"

y = Int(s1)
y = Int(s2)

情况2. 对象创建时属性还没赋值

class ViewController: UIViewController {
var button: UIButton!
} 

情况3. 函数传值为nil. (在swift里,nil是个值,表示值缺失,但在OC里,nil是个空指针)

Example: Picking up groceries in an optional car

func pickUpGroceries(car:Car?) {
if let car = car {
    print("We'll pick up the groceries in the \(car.make)")
} else {
    print("Let's walk to the store")
}
}

var someCar = Car(make: "Toyota", model: "Corolla")

pickUpGroceries(someCar)

pickUpGroceries(nil)

Example: Hosting a guest in an optional extra room

func host(guest: String, extraRoom: Room?) {
if let extraRoom = extraRoom {
    print("Come stay with us, \(guest), you can sleep in the \(extraRoom.name).")
} else {
    print("Come stay with us, \(guest), you can sleep on the couch.")
}
}

var someRoom = Room(name: "guest room", occupied: false)
host("Grandma", extraRoom: someRoom)
host("Ryan", extraRoom: nil)

使用if let强制解析(安全)

可选类型的变量就像一个盒子,里面不知道是否装着礼物。使用前必须要打开它确定是否有无,就是强制解析.

1

var zee: Int?

let strings = ["ABC","123"]
let randomIndex = Int(arc4random() % 2)
let anotherString = strings[randomIndex]

zee = Int(anotherString)

if let intValue = zee {
intValue * 2
} else {
"No value"
}

更为便捷的命名方式,不用再重新命名

var zee: Int?

let strings = ["ABC","123"]
let randomIndex = Int(arc4random() % 2)
let anotherString = strings[randomIndex]

zee = Int(anotherString)

if let zee = zee {
zee * 2
} else {
"No value"
}

使用!强制解析

2

Example 1 - unwrap optional

使用!时,意味着你确定值是不为nil的,否则就会系统出错。要谨慎使用

let w =  Int("123")!
w * 2

Example 2 - implicitly unwrap optionl

一开始就声明它是个需要强制解析的optionl类型,意味着使用时,它会自动unwrap

class BetterViewController: UIViewController {
var myButton: UIButton!

override func viewDidLoad(){

super.viewDidLoad

//如果没有这行,就会报错,因为没有初始化,UIButton就是nil
button = UIButton()

var title = button.titleForState(UIControlState.Normal)

}

}

可选链

强制解析image,获取其size属性

var imageView = UIImageView()
imageView.image = UIImage(named:"puppy_in_box")

if let image =  imageView.image {
let size = image.size
} else {
print("This image hasn't been set.")
}

使用可选链直接访问size属性

var size = anotherImageView.image?.size

可选链unwrap image, if let unwrap size, 这样更安全

var anotherImageView = UIImageView()
anotherImageView.image = UIImage(named:"puppy_in_box")

var size = anotherImageView.image?.size

if let imageSize = anotherImageView.image?.size {

print("Here's the image size: \(imageSize)")

} else {

print("This image hasn't been set.")
}

Example 2 (传值为nil)

var animal = Animal(name: "Lenny", species: "lemur", tailLength: 12)

animal = Animal(name: "Gilbert", species: "Gorilla", tailLength: nil )

if let tailLength = animal.tail?.length {
print("\(animal.name)'s tail is \(tailLength) long")
} else {
print("\(animal.name) doesn't have a tail.")
}

as? or as! 转换为子类

ColdDrink, HotDrink是 beverage的子类, drinkChoices是他们的集合

for beverage in drinkChoices{

//强制解析为subclass
if let coldDrink = beverage as? ColdDrink {

    print(.....)

}else if let hotDrink = beverage as? HotDrink {

    print(.....)
}

}

如果确定的话,使用as!,就不必使用if let了

for beverage in drinkChoices{

//强制解析为subclass
let coldDrink = beverage as!ColdDrink {

    print(.....)

}
}

运算符

swift赋值

var a: Int  //该表达式没有值
var b = a = 20  //不支持连续赋值

求余运算

var g = 5.2 (结果正负取决于被除数的正负)
var h = 3.1
var mod = g % h
print(mod)

自增自减

Swift1.x

//结果是11,先执行运算,然后a再自加1
var a = 5
var b = a++ + 6
print(b) 

//结果是12,先自身加1,再执行运算
var a = 5
var b = ++a + 6
print(b)  

Swift2.x

a -=1
a +=1

Swift3.x将取消 ++ 运算符

溢出运算符

//&+ &- &* &/ &% 执行的是位运算
var willUnderflow = UInt8.min //最小值是0
willUnderflow = willUnderflow &-1 //下溢

位运算符

& 按位与
| 或
^ 异或
~ 取反
<< 左位移
右位移 >>

扩展后的赋值运算符

-=
*=
/=
&=
|=
运算符 “+= ” 对于 x+=y 等价于 x = x+y

区间运算符

a..<b (包含a,但不包含b)
a…b(包含a,也包含b)

1
2
3
for a in 0..<10{
print(a)
}
1
2
3
for a in 0...10{
print(a)
}

比较运算符,结果为BOOL值

只有a和b指向的类型实例相同时,c为true

var c= a === b 
  1. === 特征相等运算符
  2. !== 特征不等运算符

例子

let ticketPrice = 7.5
let allowance = 10.0
var iceCreamPrice = 3.0

var pic = UIImage(named:"Chloe.png")!

if allowance >= ticketPrice + iceCreamPrice {

print("Let's go to the movies!")

} else {

print("Let's watch a movie at home and eat ice cream")

}

逻辑运算符

&& 与
|| 或
! 非

空合并运算符 a??b

  1. a是可选类型,将对可选类型a进行空判断,如果a包含一个值就进行解封
  2. 否则就返回一个默认值b
  3. 默认值b的类型必须要和a存储值的类型保持一致
1
2
3
4
let words = "hello"
var say: String?
var content = say ?? words
print(content)

流程控制

分支结构

if…else…

语句的条件执行体必须放在花括号中,条件语句不用括号

var hungry = true
var vegetarian = false

if hungry {

print("Let's eat!") 
}else{
print("Let's wait.")
}

if hungry && !vegetarian {

print("Let's eat steak!")
} else if hungry && vegetarian {
print("How about pumpkin curry?")
} else {
print("nevermind")
}

三目运算符 - Ternary conditional

以下两种写法相等

if question { answer1 } else { answer2 }

question ? answer1 : answer2

例子1.

hungry ? print("Let's eat!") : print("Let's wait.")

例子2.

hungry || thereIsPie ? print("Let's eat!") : print("Let's wait.")

例子3.

// Ternary statements can also be used as expressions.
let sandwichPrice = 5.0
var tax = true
var lunchPrice = sandwichPrice + (tax ? 0.50 : 0)

Switch -

格式:case后可以有多个值,每条语句执行完后自动退出

switch variable {
case firstValue:
statement
case secondValue:
statement
case thirdValue, fourthValue:
statement
default:
statement 
}

case后可以是个范围

var color = ""
var wavelength = 568

switch wavelength {
case 380...450:
color = "violet"
case 451...495:
color = "blue"
case 496...570:
color = "green"
case 571...590:
color = "yellow"
case 591...620:
color = "orange"
case 621...750:
color = "red"
default:
color = "not visible"
}

case后的条件为元组

var point = (x:5 , y:2)

switch point {
case (0,0):
    print("(0,0)位于原点")
case (_,0):   //用 "_" 表示可以忽略这个数据
    print("(\(point.0),0)位于x轴上")
case (0...Int.max as ClosedInterval, 0...Int.max as ClosedInterval):
    print("(\(point.0),\(point.1))位于第一象限")
default:
    break
}

使用fallthrough语句才能贯穿,否则不再继续执行下一条

    var num = 5
    var desc = "\(num)是"
    switch num {
    case 2, 3, 5, 7 :
     desc += "质数,而且还是"
     fallthrough
default:
     desc += "整数"
}
print(desc) //结果是“5是质数,而且还是整数”

支持值绑定

var point = (x:1 , y:1)
switch point {
case (0,0):
   print("(0,0)位于原点")
case (var a, 0)://y坐标为0,进入该case块,并将元组的x成员绑定到临时变量a
   print("该点位于x轴上,x值为:\(a)")
case var (x,y) where x>0 && y>0:  //条件值绑定
   print("(\(x),\(y))位于第一象限")
default:
   break
}

循环结构

for loop

传统的C - style for loop (swift也支持)

for var index = 99; index >0; --index {

print ("Hello") 

}

更为简洁的形式

for item in Collection {
statements to execute on each item
}

例子1

for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}

例子2 不访问index的值

let base = 3
let power = 10
var answer = 1
for _ in 1...power { //下划线符号_替代循环中的变量,能够忽略具体的值,并且不提供循环遍历时对值的访问
  answer *= base
}

例子3 遍历数组累加

let intArray = [7, 21, 25, 13, 1]
var sum = 0
for value in intArray {
sum += value
}

例子4 遍历字典value值替换key值

 for (key, value) in Dictionary {

 statement to execute on each key or value

 }    


let dictionary = ["monkey": "🐒", "iPhone":"📱"]
var newestString = sillyMonkeyString

for (key, value) in dictionary {
newestString = newestString.stringByReplacingOccurrencesOfString(key, withString: value)
}

print(newestString)

嵌套循环遍历时使用的标签

  1. 紧跟冒号的标识符,只有放在循环语句或者switch语句之前才有作用
  2. break结束循环,开始执行循环之后的代码
  3. continue 忽略本次循环的剩下语句,执行下一次循环,但不终止循环
1
2
3
4
5
6
7
8
9
outer: for i in 0...5 {
//内层循环
for j in 0...3{
print("i的值为:\(i),j的值为\(j)")
if j==1 {
break outer
}
}
}

while … loop

while condition {
statement
}


var timer = 10

while timer > 0 {
timer -= 1
}

repeat … loop

repeat {
statement
} while condition


repeat {
 --timer
} while timer > 0