Swift 简介
-
苹果公司2014年WWDC 推出 开源 语言
-
适用于iOS7+ 及 OS X Mavericks+的应用开发
-
Swift 语言与之前的Objectiv-C可共存(可以调用OC写的代码库,嵌入OC代码之中)
-
Swift 语言不向下兼容,3.0以上逐渐稳定,相互兼容 Swift3.0 与 2.x语法不一致,不能兼容与混用
-
Swift从Python和Javascript中学了设计优点 Swift是语法类似脚本语言的编译型语言
playground - 游乐园
-
Playground是苹果公司在2014年WWDC(苹果开发者大会)
-
随Swift一起推出 Playground支持一边写代码,一边预览效果
-
可以看到输出的常量变量的值
-
实时预览代码的效果
-
优点:实时、不需要运行模拟器
Swift特点
-
强类型安全
-
大小写敏感
-
结尾没有分号
-
注释语法和 C 一样
常量、变量
-
使用 let 来声明常量
-
使用 var 来声明变量
-
可以不明确声明类型,赋值时编译器会自动类型推断
var myVariable = 42
myVariable = 50
let myConstant = 42.5
- 如果初始值没有提供足够的信息(或者没有初始值),需要在变量后面声明类型,用冒号分割
let explicitDouble : Double = 70
let stringLabel : String
- 一个值不能隐式转换为其他类型
如果把一个值转换成其他类型,需要显式转换
let label = "The width is"
let width = 94
let widthLabel = label + String(width)
字符串插值(String Interpolation)
使用字符串插值符号 ( ) 可以更简单的把数据值转换成字符串
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
print( "She has \(oranges) oranges.")
基本数据类型
基本运算符
数组和字典
-
使用方括号[]来创建数组和字典,并使用下标或者键(key)来访问元素,元素下标从 0 开始
-
最后一个元素后面允许有个逗号
数组
var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
字典
var occupations = [ "Malcolm": "Captain","Kaylee": "Mechanic"]
occupations["Jayne"] = "Public Relations"
- 创建一个空数组或者字典,使用初始化语法。
数组:let emptyArray = String
字典:let emptyDictionary = String: Float
- 如果类型信息在添加值时可以被推断出来,则可以用[]和[:]来创建空数组和空字典
数组: let shoppingList = []
字典: let occupations = [:]
元组
-
概念类似于python中的元组
-
元组是多个值组合而成的复合值,用 ( ) 表示
-
元组中的值可以是任意类型,而且每一个元素的类型可以是不同的
-
当函数需要返回若干值时,可以利用元组一次性返回多个值
定义:let amout = (100, “EUR”)
- 元组可以分解,可以使用下标方式来访问元组中的每个值:
let currency = amout.1 // " EUR"
- 可以给元组每个元素命名:
let money = (amount: 100, currency: " EUR ")
- 通过名字访问元素:
let currency = money.currency // "EUR "
- 元组在分解时,可以只分解部分值,而忽略其它值,其它值可以用下划线_来代替:
let (currency , _) = money
元组、数组、字典特点对比
特点 | 元组 | 数组 | 字典 |
---|---|---|---|
特点 | 综合了数组、字典、甚至 struct 的一些优点 对数据类型的一个强力补充 |
C 的数组只能存储多个相同类型的数据 OC,Swift 不再限定存储数据的类型 |
字典是 key:value 键值对,它适合将不同种类、不同用途的数据组合在一起,通过key值进行索引 |
优点 | 元组可同时存储 多种类型元素,且元素类型固定,以保证数据安全,除非定义数据类型为Any,编译器会对赋值参数类型进行检查 元组的元素个数固定,不允许增加、删除,编译器会严格校验赋值参数个数 无需定义key,但是必要时可以为数据命名,方便数据访问,适合同时遍历多元数据,例如官方文档的例子: for (index, value) in shoppingList.enumerate() {…} |
数据存储顺序固定,增删改也通过index来进行 集成了遍历方法,适合对大量同类数据的处理 不需要定义key,写法相对简单 |
通过key值进行索引,查找效率高 通过key值进行数据标注,可读性高,易于区分多种数据key 值唯一,增删改可以保证数据唯一性 |
缺点 | 不适合存储大量数据,因为元组不支持append、remove等方法 考虑到工程实际情况,后端使用的语言可能不支持元组,需要转换为其他格式 元组适合应用于组合少量的多元的数据 |
访问特定数据时,查找效率不高 处理特定数据时,需要牢记数据的index,可读性不好,容易产生错位处理 |
一个value必须对应一个key,尽管有时不需要key值 顺序不定,字典对key值表进行了hash,所以不方便存储对顺序敏感的数据 |
控制流
-
使用 if 和 switch 来进行条件操作
-
使用for-in、for、while和repeat-while进行循环
-
包裹条件和循环变量括号可以省略,但是语句体必须有大括号
-
去掉了 ++,–及for(i=0;i<x;i++)的形式,一律用for…in 代替
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 60 {
teamScore += 3
}
teamScore += 1
}}
print(teamScore)
可选绑定(optional binding)
-
使用可选绑定(optional binding)来判断可选类型是否包含值
-
如果有值就赋值给临时常量或变量
var optionalName: String?
var greeting = "Hello! "
optionalName = "Hillary Clinton"
if let name = optionalName {
greeting = "Hello, \(name)"
else {
print(" optionalName is nil")
}
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.")}
while
var n = 2
while n < 100 {
n = n * 2
}
print(n)
repeat … while
类似do…while
var m = 2
repeat {
m = m * 2
} while m < 100
print(m)
使用 …< 创建的范围不包含上界,包含上界需要使用 …
var firstForLoop = 0
for i in 0..<4 {
firstForLoop += i
}
var myLoop = 0
for _ in 0…5 {
myLoop += 10
}
函数
-
使用func来声明一个函数,使用名字和参数来调用函数
-
使用->来指定函数返回值的类型
func greet(person : String, day: String) -> String { return “Hello (name), today is (day).”}
- 调用:第一个参数名(或参数描述)必须带上
greet(person:“Bob”, day: “Tuesday”)
- 函数默认使用参数名作标签,也可以指定参数标签,同时用 _ 表示没有参数标签
func greet( _ person : String, on day: String) -> String { return “Hello (person), today is (day).”}
- 调用时,空标签可以省略
greet(“John”, on:“Wednesday”)
- 使用元组返回多个值
该元组的元素可以用名称或数字来表示
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int)
{
var min = scores[0]
var max = scores[0]
for score in scores {
if score > max {
max = score
}
else if score < min {
min = score
}
}
return (min, max)
}
let statistics = calculateStatistics(scores:[5, 12, 100, 3, 9])
print(statistics. min); print(statistics.1)
- 函数可以带有可变个数的参数
这些参数在函数内表现为数组,可以循环遍历
func sumOf(numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
sumOf()
sumOf(numbers: 42, 597, 12)
Optional
Optional理解
Swift语言使用 var 定义变量,但Swift不会自动给变量赋初始值
。因此变量不会有默认值,所以使用变量之前必须对其初始化。使用变量之前不进行初始化就会编译报错。可以避免发生因为使用了未初始化的值而引发的潜在的运行时错误
可以使用optional类型来处理,即在后面跟一个?。?表示变量可能有值,也可能是 nil (空对象) – 类似NULL(空指针)。声明?之后,变量就成为了optional types(可选类型)。即对变量打包,提取值时需要拆包操作
var strValue: String?
//判断optional是否有值,不会报错
if strValue != nil {
// do what you need to do here
} else { //strValue is nil
}
可选绑定
var strValue: String?
…
if let hashValue = strValue?.hashValue {
// do what you need to do here
} else {
//strValue is nil
}
如果strValue == nil, 那么结果就是nil,不会调用String的hasValue方法
如果strValue != nil, 就返回strValue对应的hashValue值并赋值给常量hashValue
使用!来强制拆包(提取值),在保证有值的情况下才会这么用
var strValue: String?
strValue = "1234"
let integer = Int(strValue!)
更安全的写法是:
先判断是否有值(去掉定义的?再执行试试)
if strValue != nil {
let integer = Int(strValue!)
}
Optional 本质
Optional其实是个enum(枚举),里面有None和Some两种类型
其实所谓的 nil 就是Optional.None, 非nil就是Optional.Some
通过Some(T)包装(wrap)原始值
在使用Optional的时候要拆包(从enum里取出来原始值)
闭包
- 闭包就是在函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层函数体中的临时变量
- 从定义上看,所有的函数都可以是闭包
- 当一个函数调用时,引用了不是自己作用域内定义的变量(通常称其为自由变量),则形成了闭包
- 闭包是代码块和创建该代码块的上下文中数据的结合
- 闭包形式1:函数的嵌套
特点:闭包可以在其定义的上下文中捕获常量或变量
用途:可以重构一个太长或者太复杂的函数
func returnFifteen() -> Int {
var y = 10
func add() {
y += 5
}
add()
return y
}
returnFifteen()
- 函数是第一等类型
可以作为另一个函数的返回值
func makeIncrementer() -> ((Int) -> Int) {
var number = 0
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne}
var increment = makeIncrementer()
increment(7)
- 闭包形式2:函数也可以当做参数传入另一个函数
- 函数实际上是一种特殊的闭包:它是一段能之后被调取的代码
- 闭包是功能性自包含模块,可以在代码中被传递和使用
- Swift 中的闭包与 C 和 Objective-C中的 blocks 以及其他一些编程语言中的 lambdas 比较相似
- 闭包常用形式:
使用 { } 来创建一个匿名闭包 – 没有 func 函数名称
使用 in 将参数和返回值类型声明与闭包函数体进行分离
numbers.map ( {
(number: Int) -> Int in
let result = 3 * number
return result} )
- 可以在闭包中定义参数,返回值
- 闭包后用括号执行,并在括号中可以传参
- Swift 自动为内联函数提供了参数名称简写功能,可以直接通过 $0,$1,$2等名字来引用的闭包的参数的值
尾随闭包
- 如果需要将一个很长的闭包表达式作为最后一个参数传递给函数可以使用尾随闭包来增强函数的可读性
- 尾随闭包是一个书写在函数括号之外(之后)的闭包表达式,函数支持将其作为最后一个参数调用
func calculate(opr: String, funN:(Int, Int) -> Int) {
// 函数体部分
}
- 最后一个参数funN是(Int,Int)-> Int函数类型
- funN可以接收闭包表达式
- 普通调用,闭包体在()内
calculate("+", funN: {(a: Int, b: Int) -> Int in return a + b })
- 使用尾随闭包进行函数调用 1 ,闭包体在()外
calculate("+"){
(a: Int, b: Int) -> Int in
return a + b
}
- 使用尾随闭包进行函数调用 2 ,简写方式
calculate("+") { $0 + $1 }
例子
func makeIncrementor(forIncrement amount: Int) -> (() -> Int) {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
var incrementByTen = makeIncrementor(forIncrement: 10)
print(incrementByTen())
print(incrementByTen())
print(incrementByTen())
- makeIncrementor 返回类型为 () -> Int, 说明其返回的是函数,不是类型值
incrementor 函数并没有带参数,但是在函数体内引用外层函数的临时变量: runningTotal 和 amount - 只要目标对象(incrementor
函数)在生存期内,就能始终能保持其方法,也能间接保持外层函数体定义的临时变量值
尽管外层函数调用已经结束,临时变量的名称也消失,但在目标对象的方法内却始终能引用到该变量的值,而且该值只能通这种方法来访问 - 即使再次调用相同的外层函数,但只会生成新对象和方法,新的临时变量只是对应新的值,和上次那次调用的是各自独立的
- Swift 会决定捕获引用还是拷贝值
- 如果一个值没有改变或者在闭包的外面,Swift 可能会使用这个值的拷贝而不是捕获
- Swift 同时也处理 runingTotal 变量的内存管理操作,如果不再被 incrementor 函数使用,临时变量会被清除
- 如果创建了另一个 incrementor,其会有一个属于自己的独立的 runningTotal 变量的引用。
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
incrementByTen()
上课时的代码
变量,常量
// ---------------------------------------
// 课堂演示2.2 Swift基础(1):创建命令行工程。
// 内容:创建一个OS X命令行项目,生成并运行。
print("Hello, My First Swift Project!")
// ---------------------------------------
// 课堂练习2.2 Swift基础(2):语句与输出。
// 内容:输入字符串“我是xxxx,我喜欢iOS开发”。
print("我是李老师,我喜欢iOS开发")
// ---------------------------------------
// 课堂演示2.2:Swift基础(3):变量与常量。
// 内容:创建一个常量,常量名为PI,初始值为3.14。创建一个变量,变量名为r,显式指定类型为Double并指定初始值为10。
let PI = 3.14 // let定义常量,自动推断类型为Double
var radius:Double = 10 // var定义变量,显式指定数据类型为Double
// ---------------------------------------
// 课堂演示2.2:Swift基础(4):元组。
// 内容:使用元组存储你的信息,并输出。
// 1) 定义元组
let myInfo1 = ("liwei", 35) // 定义元组
let myInfo2: (String, Int) = ("liwei", 35)
var myInfo3 = (name:"liwei", age:35) // 定义元组:指定元素名称
// 2) 修改元组
myInfo3.name = "Yu"
myInfo3.age = 60
// 3) 使用元组
print("My name is \(myInfo1.0) and my age is \(myInfo1.1)")
print("My name is \(myInfo2.0) and my age is \(myInfo2.1)")
print("My name is \(myInfo3.name) and my age is \(myInfo3.age)")
// ------------------------------------------
// 课堂演示2.2:Swift基础(5):可选。
// 内容:编写可选代码,理解Swift可选机制。
var possibleInt: Int? = 0 // 定义可选变量
var myString = "7"
possibleInt = Int(myString)
print(possibleInt)
myString = "banana"
possibleInt = Int(myString)
print(possibleInt)
// ----------------------------------------------
// 课堂演示2.2:Swift基础(6):运算符。
// 内容:给定半径,计算圆形面积和球形体积。
var r = 10.0
var area = PI*r*r
var volume = 4/3*PI*r*r*r
print("The area is \(area), and the volume is \(volume)")
控制流
import Foundation
// 课堂演示2.3:控制流。
// 内容(1):计算1-100之和
// 内容(2):计算13的阶乘
// 内容(3):计算100以内的斐波那契数列
/////////////////////////////////////
// 1. 计算1-100之和
var sum = 0
var index = 1
while index <= 100 {
sum += index
index += 1
}
print("0-100之和是:\(sum)")
/////////////////////////////////////
// 2. 计算13的阶乘
var result = 1
var n = 13
while n > 0 {
result *= n
n -= 1
}
print("13的阶乘是:\(result)")
//////////////////////////////////////
// 2. 计算100以内的斐波那契数列
var value1 = 1
var value2 = 1
var value3 = 0
var str = "1 1 "
while true {
value3 = value1 + value2
if value3 < 100 {
str += "\(value3) "
value1 = value2
value2 = value3
} else {
break
}
}
print("100以内斐波那契数列是:\(str)")
复杂数据运算
import Foundation
// 课堂演示2.4 复杂数据类型(1):数组。
// 内容:创建字符串数组,存入一些动物名称,进行数组常用操作练习
// 创建数组
var array = [String]() // 常用
var array2 = Array<String>()
var array3 = ["小猫", "小狗", "小鸟"]
//判断数组是否为空
print(array.isEmpty)
//添加数组元素
array.append("小猫")
array.append("小狗")
array += ["小鸟"]
print(array)
//判断数组是否为空
print(array.isEmpty)
//在指定位置添加元素
array.insert("小鱼", at: 1)
print(array)
//数组元素个数
print(array.count)
//数组遍历
for item in array {
print(item)
}
//删除最后一个
array.removeLast()
print(array)
//删除指定位置元素
array.remove(at: 1)
print(array)
//删除所有元素
array.removeAll()
print(array.isEmpty)
print(array)
// -----------------------------------------------------
// 课堂演示2.4 复杂数据类型(1):数组。
// 内容(1):使用字典存储水果名称及其价格
// 内容(2):使用字典存储我们主要城市的电话区号
///////////////////////////////////////////
// 1. 使用字典存储水果名称及其价格
//创建字典
var dic = ["苹果":6.5, "葡萄":5.0, "桔子":3.0]
print(dic)
// 增加元素
dic["哈密瓜"] = 7.5
print(dic)
// 删除元素
dic.removeValue(forKey: "苹果")
print(dic)
// 遍历所有key
for key in dic.keys {
print(key)
}
// 遍历字典
for (key, value) in dic {
print("\(key)的价格是\(value)元")
}
自己的代码
import Foundation
///////////////////////////////////////////////////
func calcMaxMin(values: [Int])->(max:Int,min:Int)
{
var max = values[0]
var min = values[1]
for v in values
{
if v > max
{
max = v
}
if v < min
{
min = v
}
}
return (max,min)
}
let values=[1,2,3,4,5,6]
let maxmin = calcMaxMin(values: values)
print("max value is \(maxmin.max),min value is \(maxmin.min)")
///////////////////////////////////////////////////
func oushu(threshold: Int)
{
var number = 0
func add2()
{
number += 2
}
while number < threshold
{
print(number)
add2()
}
}
oushu(threshold: 100)
///////////////////////////////////////////////////
func mathResult(mathFunc:(Int, Int)->Int, num1: Int, num2: Int) -> Int {
return mathFunc(num1 , num2)
}
func getSmaller(num1: Int ,num2: Int) -> Int {
return(num1 < num2) ? num1 : num2
}
func addFunction(num1: Int,num2: Int) -> Int {
return num1+num2
}
var rst = mathResult(mathFunc:getSmaller,num1:1, num2:2)
print(rst)
var rst1 = mathResult(mathFunc:addFunction,num1:1,num2:2)
print(rst1)
///////////////////////////////////////////////////
func makeIncrementer()->((Int)->Int)
{
func add1(num: Int)->Int
{
return num+1
}
return add1
}
var incrementer = makeIncrementer()
var rst = incrementer(7)
print(rst)
///////////////////////////////////////////////////
var b1 = {
print("这是闭包")
}
b1()
var b2 = {
(param: String) in
print("闭包参数:\(param)")
}
b2("Thrinity")
var b3 = {
(param: String) -> String in
return "闭包参数:\(param)"
}
print(b3("Thrinity"))
var b4 = {
(p1: String, p2:String)->String in
return p1+p2
}("Holle","World")
print(b4)
var s1 = {
(p1, p2) in
return p1+p2
}("Holle","World")
print(s1)
var s2 = {
(p1, p2) in
p1+p2
}("Holle","World")
print(s2)
var s3 = {
$0+$1
}("Holle","World")
print(s3)
///////////////////////////////////////////////////
func myOperation(num1: Int,num2: Int, operation:(Int,Int)->int)->int{
let rst = operation(num1,num2)
return rst
}
let multipleClosure = {
(a:Int ,b:Int)->Int in
return a*b
}
let multipleClosure:(Int , Int)->Int = {$0*$1}
var rst = myOperation(num:1,num:2,operation:multipleClosure)
print(rst)
var rst1 = myOperation(num1:3,num2:2,operation:{(a,b)->Int in return a*b} )
var rst2 = myOperation(num1:3,num2:2){$0*$1}
///////////////////////////////////////////////////
let names=["Thrinity","Jackma","Bob","ZXC","W"]
let rst = names.sorted()
print(rst)
let rst1 = names.sorted{
$0.count > $1.count
}
print(rst1)
///////////////////////////////////////////////////
enum WeekDay{
case Mon
case Tue
case Wen
case Thu
case Fri
func description(){
switch self {
case .Mon:
print("星期一")
case .Fri:
print("星期五")
default:
print("I don't know")
}
}
}
var day = WeekDay.Mon
print(day)
day.description()
///////////////////////////////////////////////////