Swift 2.2
Chris Lattner
开始着手 Swift 编程语言的设计工作用一年时间,完成基本架构Swift 大约历经 4 年的开发期,2014 年 6 月发表克里斯·拉特纳
何许人?LLVM 项目的主要发起人与作者之一Clang 编译器的作者苹果公司『开发者工具』部门的主管领导Xcode、Instruments等编译器团队Swift的大部分基础架构均由他1人完成评价:大神中的大神牛逼中的牛逼特点特点从它的语法中能看到Objective-C、JavaScript、C#、Python等语言的影子语法简单、代码简洁、使用方便可与Objective-C混合使用(相互调用)提供了类似 Java 的名字空间(namespace)、泛型(generic)、运算对象重载(operator overloading)为什么设计Swift语言让应用开发更简单、更快、更稳定确保最终应用有着更好的质量重要性苹果目前在大力推广Swift斯坦福大学的公开课目前也是使用Swift在授课.因为以后Swift必将代替OC题外话:我们同学去面试,面试官问是否会Swift,如果会,我们下个项目直接用Swift来写.你可以教我们Swift.个人建议:先掌握Swift最基本的语法高级/特殊的功能随着学习的深入再深入研究千万不要浮躁(前面班级经验)Swift并不难但是语法和OC区别非常非常大如果是一个听一听,听不懂就算了的心态.一定是学不好的如果想要学习,就认真听讲,好好练习资源网站《The Swift Programming Language》中文版 http://numbbbbb.gitbooks.io/-the-swift-programming-language-/swifter 作者王巍,需要付费购买 http://onevcat.comSwift初体验Playground是什么?从Xcode6开始出现(Swift开始出现)翻译为:操场/游乐场对于学习Swift基本语法非常方便所见即所得(快速查看结果)语法特性发生改变时,可以快速查看.Swift最基本的语法变化导入框架 import UIKit定义标识符时,必须声明该标识符是变量还是常量声明标识符的格式:变量/常量关键字 名称 : 数据类型语句结束时不需要加;如果同一行有多个语句,则依然需要加但是不建议一行多条语句Swift中的打印语句:print(打印的内容)常量&变量什么是常量和变量在Swift中规定:在定义一个标识符时必须明确说明该标识符是一个常量还是变量使用let来定义常量,定义之后不可以修改使用var来定义变量,定义之后可以修改变量的基本使用import UIKitlet a : Int=10// 错误写法,当一个字段定义为常量时是不可以修改的// a=20var b : Int=20// 因为b定义为变量,因此是可以修改的b=30
常量和变量的使用注意:注意:
在真实使用过程中,建议先定义常量,如果需要修改再修改为变量(更加安全)是指向的对象不可以再进行修改.但是可以通过指针获得对象后,修改对象内部的属性 // 注意:声明为常量不可以修改的意思是指针不可以再指向其他对象.但是可以通过指针拿到对象,修改其中的属性 // view : UIView=[[UIView alloc] init]; // Swift对象中不需要* var view : UIView=UIView() view=UIView() let view1 : UIView=UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) view1.backgroundColor=UIColor.redColor() // 枚举类型的用法:类型.枚举的值 let btn : UIButton=UIButton(type: UIButtonType.Custom) btn.backgroundColor=UIColor.blueColor() btn.setTitle("按钮", forState: UIControlState.Normal) btn.frame=CGRect(x: 20, y: 20, width: 60, height: 30) view1.addSubview(btn)
Swift中数据类型Swift类型的介绍Swift中的数据类型也有:整型/浮点型/对象类型/结构体类型等等
先了解整型和浮点型
整型
有符号Int8 : 有符号8位整型Int16 : 有符号16位整型Int32 : 有符号32位整型Int64 : 有符号64位整型Int : 和平台相关(默认,相当于OC的NSInteger)无符号UInt8 : 无符号8位整型UInt16 : 无符号16位整型UInt32 : 无符号32位整型UInt64 : 无符号64位整型UInt : 和平台相关(常用,相当于OC的NSUInteger)(默认)浮点型
Float : 32位浮点型Double : 64浮点型(默认)// 定义一个Int类型的变量m,并且赋值为10var m : Int=10// 定义一个Double类型的常量n,并且赋值为3.14let n : Double=3.14
Swift中的类型推导Swift是强类型的语言
Swift中任何一个标识符都有明确的类型
注意:
如果定义一个标识符时有直接进行赋值,那么标识符后面的类型可以省略.因为Swift有类型推导,会自动根据后面的赋值来决定前面的标识符的数据类型可以通过option
+鼠标左键
来查看变量的数据类型 // 定义变量时没有指定明确的类型,但是因为赋值给i一个20.20为整型.因此i为整型 var i=20 // 错误写法:如果之后赋值给i一个浮点型数值,则会报错 // i=30.5 // 正确写法 var j=3.33 j=6.66
Swift中基本运算Swift中在进行基本运算时必须保证类型一致,否则会出错
相同类型之间才可以进行运算因为Swift中没有隐式转换数据类型的转化
Int类型转成Double类型:Double(标识符)Double类型转成Int类型:Int(标识符) let a=10 let b=3.14 // 错误写法 // let c=a + b // let c=a * b // 正确写法 let c=Double(a) + b let d=a + Int(b)
逻辑分支一. 分支的介绍分支即if/switch/三目运算符等判断语句通过分支语句可以控制程序的执行流程二. if分支语句和OC中if语句有一定的区别
判断句可以不加()在Swift的判断句中必须有明确的真假不再有非0即真必须有明确的Bool值Bool有两个取值:false/true // 演练一: let a=10 // 错误写法: //if a { // print("a") //} // 正确写法 if a > 9 { print(a) } // 演练二: let score=87 if score < 60 { print("不及格") } else if score <=70 { print("及格") } else if score <=80 { print("良好") } else if score <=90 { print("优秀") } else { print("完美") } // 演练三: // 这个是可选类型,因为只有声明成可选类型后,才可以判断是否为空 // 可选类型会在后续讲解,可先了解即可 let view : UIView?=UIView() // 判断如果view有值,则设置背景 // 错误写法 //if view { // view.backgroundColor=UIColor.redColor() //} if view !=nil { view!.backgroundColor=UIColor.redColor() }
三. 三目运算符Swift
中的 三目
运算保持了和 OC
一致的风格
var a=10var b=50var result=a > b ? a : bprintln(result)
四.guard的使用guard是Swift2.0新增的语法
它与if语句非常类似,它设计的目的是提高程序的可读性
guard语句必须带有else语句,它的语法如下:
当条件表达式为true时候跳过else语句中的内容,执行语句组内容 guard 条件表达式 else { // 条换语句 break } 语句组
例子
var age=18 func online(age : Int) -> Void { guard age >=18 else { print("回家去") return } print("可以上网") } online(age)
四.switch分支switch的介绍Switch作为选择结构中必不可少的语句也被加入到了Swift中只要有过编程经验的人对Switch语句都不会感到陌生但苹果对Switch进行了大大的增强,使其拥有其他语言中没有的特性switch的简单使用基本用法和OC用法一致
不同之处:
switch后可以不跟()case后可以不跟break(默认会有break)例子:
let sex=0 switch sex { case 0 : print("男") case 1 : print("女") default : print("其他") }
简单使用补充:
一个case判断中,可以判断多个值多个值以,
隔开 let sex=0 switch sex { case 0, 1: print("正常人") default: print("其他") }
简单使用补充:
如果希望出现之前的case穿透,则可以使用关键字fallthrough
let sex=0 switch sex { case 0: fallthrough case 1: print("正常人") default: print("其他") }
Switch支持多种数据类型浮点型的switch判断
let f=3.14 switch f { case 3.14: print("π") default: print("not π") }
支持字符串类型
字符串的使用后面会详细讲解 let m=5 let n=10 var result=0 let opration="+" switch opration { case "+": result=m + n case "-": result=m - n case "*": result=m * n case "/": result=m / n default: result=0 } print(result)
switch支持区间判断什么是区间?
通常我们指的是数字区间:010,100200swift中的区间常见有两种
半开半闭区间:0..<10 表示:0~9,不包括10闭区间:0...10 表示:0~10 let score=88 switch score { case 0..<60: print("不及格") case 60..<80: print("几个") case 80..<90: print("良好") case 90..<100: print("优秀") default: print("满分") }
循环的介绍在开发中经常会需要循环常见的循环有:for/while/do while.这里我们只介绍for/while,因为for/while最常见for循环的写法最常规写法
// 传统写法 for var i=0; i < 10; i++ { print(i) }
区间for循环
for i in 0..<10 { print(i) } for i in 0...10 { print(i) }
特殊写法
- 如果在for循环中不需要用到下标i for _ in 0..<10 { print("hello") }
while和do while循环while循环
while的判断句必须有正确的真假,没有非0即真while后面的()可以省略 var a=0 while a < 10 { a++ }
do while循环
使用repeat关键字来代替了do let b=0 repeat { print(b) b++ } while b < 20
字符串的介绍字符串在任何的开发中使用都是非常频繁的OC和Swift中字符串的区别在OC中字符串类型时NSString,在Swift中字符串类型是StringOC中字符串@"",Swift中字符串""使用 String
的原因String
是一个结构体,性能更高NSString
是一个 OC
对象,性能略差String
支持直接遍历Swift
提供了 String
和 NSString
之间的无缝转换字符的定义定义不可变字符串
let str="hello Objective-C"
定义可变字符串
var str="hello Swift"
字符串的使用获取字符串的长度获取字符集合,再获取集合的count属性
let count=str.characters.count
遍历字符串 // 字符串遍历 var str="Hello, Swift" for c in str.characters { print(c) }
字符串拼接两个字符串的拼接
let str1="Hello" let str2="World" let str3=str1 + str2
字符串和其他数据类型的拼接
let name="why" let age=18 let info="my name is \(name), age is \(age)"
字符串的格式化
比如时间:03:04 let min=3 let second=4 let time=String(format: "%02d:%02d", arguments: [min, second])
字符串的截取Swift中提供了特殊的截取方式
该方式非常麻烦Index创建较为麻烦简单的方式是将String转成NSString来使用
在标识符后加:as NSString即可 let myStr="www.baidu.com" var subStr=(myStr as NSString).substringFromIndex(4) subStr=(myStr as NSString).substringToIndex(3) subStr=(myStr as NSString).substringWithRange(NSRange(location: 4, length: 5))
swift截取方式
// 1.定义字符串 let str="www.baidu.com" // 2.截取开始位置 let fromIndex=str.startIndex.advancedBy(3) let header=str.substringFromIndex(fromIndex) // 3.截取结束位置 let toIndex=str.endIndex.advancedBy(-3) let footer=str.substringToIndex(toIndex) // 4.截取中间的字符串 let range=Range(start: str.startIndex.advancedBy(4), end: str.endIndex.advancedBy(-4)) let middle=str.substringWithRange(range)
数组数组的介绍数组(Array)是一串有序的由相同类型元素构成的集合数组中的集合元素是有序的,可以重复出现Swift中的数组swift数组类型是Array,是一个泛型集合数组的初始化数组分成:可变数组和不可变数组
使用let修饰的数组是不可变数组使用var修饰的数组是可变数组 // 定义一个可变数组,必须初始化才能使用 var array1 : [String]=[String]() // 定义一个不可变数组 let array2 : [NSObject]=["why", 18]
在声明一个Array类型的时候可以使用下列的语句之一
var stuArray1:Array<String> var stuArray2: [String]
声明的数组需要进行初始化才能使用,数组类型往往是在声明的同时进行初始化的
// 定义时直接初始化 var array=["why", "lnj", "lmj"] // 先定义,后初始化 var array : Array<String> array=["why", "lnj", "lmj"]
对数组的基本操作 // 添加数据 array.append("yz") // 删除元素 array.removeFirst() // 修改元素 array[0]="why" // 取值 array[1]
数组的遍历 // 遍历数组 for i in 0..<array.count { print(array[i]) } // forin方式 for item in array { print(item) } // 设置遍历的区间 for item in array[0..<2] { print(item) } // 遍历数组的同时获取下标值 let names=["why", "yz", "lnj", "lmj"] for (index, name) in names.enumerate() { print(index) print(name) }
数组的合并 // 数组合并 // 注意:只有相同类型的数组才能合并 var array=["why", "lmj","lnj"] var array1=["yz", "wsz"] var array2=array + array1; // 不建议一个数组中存放多种类型的数据 var array3=[2, 3, "why"] var array4=["yz", 23] array3 + array4
字典字典的介绍字典允许按照某个键来访问元素字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合键集合是不能有重复元素的,而值集合是可以重复的,键和值是成对出现的Swift中的字典Swift字典类型是Dictionary,也是一个泛型集合字典的初始化Swift中的可变和不可变字典
使用let修饰的数组是不可变字典使用var修饰的数组是可变字典 // 定义一个可变字典 var dict1 : [String : NSObject]=[String : NSObject]() // 定义一个不可变字典 let dict2=["name" : "why", "age" : 18]
在声明一个Dictionary类型的时候可以使用下面的语句之一
var dict1: Dictionary<Int, String> var dict2: [Int: String]
声明的字典需要进行初始化才能使用,字典类型往往是在声明的同时进行初始化的
// 定时字典的同时,进行初始化 var dict=["name" : "why", "age" : 18]
// swift中任意对象,通常不使用NSObject,使用AnyObjectvar dict : Dictionary<String, AnyObject>dict=["name" : "why", "age" : 18]?```
字典的基本操作 // 添加数据 dict["height"]=1.88 dict["weight"]=70.0 dict // 删除字段 dict.removeValueForKey("height") dict // 修改字典 dict["name"]="lmj" dict.updateValue("lmj", forKey: "name") dict // 查询字典 dict["name"]
字典的遍历 // 遍历字典中所有的值 for value in dict.values { print(value) } // 遍历字典中所有的键 for key in dict.keys { print(key) } // 遍历所有的键值对 for (key, value) in dict { print(key) print(value) }
字典的合并 // 字典的合并 var dict1=["name" : "yz", "age" : 20] var dict2=["height" : 1.87, "phoneNum" : "+86 110"] // 字典不可以相加合并 for (key, value) in dict1 { dict2[key]=value }
元组元组的介绍元组是Swift中特有的,OC中并没有相关类型它是什么呢?它是一种数据结构,在数学中应用广泛类似于数组或者字典可以用于定义一组数据组成元组类型的数据可以称为“元素”元组的定义元组的常见写法
// 使用元组描述一个人的信息 ("1001", "张三", 30, 90) // 给元素加上元素名称,之后可以通过元素名称访问元素 (id:"1001", name:"张三", english_score:30, chinese_score:90)
元组的简单使用用元组来描述一个HTTP的错误信息
// 元组:HTTP错误 // let array=[404, "Not Found"] // 写法一: let error=(404, "Not Found") print(error.0) print(error.1) // 写法二: let error=(errorCode : 404, errorInfo : "Not Found") print(error.errorCode) print(error.errorInfo) // 写法三: let (errorCode, errorIno)=(404, "Not Found") print(errorCode) print(errorIno)
可选类型可选类型的介绍注意:可选类型时swift中较理解的一个知识点暂时先了解,多利用Xcode的提示来使用随着学习的深入,慢慢理解其中的原理和好处概念:在OC开发中,如果一个变量暂停不使用,可以赋值为0(基本属性类型)或者赋值为空(对象类型)在swift开发中,nil也是一个特殊的类型.因为和真实的类型不匹配是不能赋值的(swift是强类型语言)但是开发中赋值nil,在所难免.因此推出了可选类型可选类型的取值:空值有值定义可选类型定义一个可选类型有两种写法
最基本的写法语法糖(常用) // 错误写法 // let string : String=nil // 正确写法: // 注意:name的类型是一个可选类型,但是该可选类型中可以存放字符串. // 写法一:定义可选类型 let name : Optional<String>=nil // 写法二:定义可选类型,语法糖(常用) let name : String?=nil
可选类型的使用 // 演练一:给可选类型赋值 // 定义可选类型 var string : Optional<String>=nil // 给可选类型赋值 // 错误写法:因此该可选类型中只能存放字符串 string=123 // 正确写法: string="Hello world" // 打印结果 print(string) // 结果:Optional("Hello world")\n // 因为打印出来的是可选类型,所有会带Optional // 演练二:取出可选类型的值 // 取出可选类型的真实值(解包) print(string!) // 结果:Hello world\n // 注意:如果可选类型为nil,强制取出其中的值(解包),会出错 string=nil print(string!) // 报错 // 正确写法: if string !=nil { print(string!) } // 简单写法:为了让在if语句中可以方便使用string // 可选绑定 if let str=string { print(str) }
真实应用场景目的:让代码更加严谨
// 通过该方法创建的URL,可能有值,也可能没有值. // 错误写法:如果返回值是nil时,就不能接收了 // 如果字符串中有中文,则返回值为nil,因此该方法的返回值就是一个可选类型,而使用一个NSURL类型接收是错误的 let url : NSURL=NSURL(string: "www.baidu.com") // 正确写法:使用可选类型来接收 let url : NSURL?=NSURL(string: "www.baidu.com") // 该方式利用类型推导 let url=NSURL(string: "www.baidu.com") // 通过url来创建request对象:在使用可选类型前要先进行判断是否有值 // 该语法成为可选绑定(如果url有值就解包赋值给tempURL,并且执行{}) if let tempUrl=url { let request=NSURLRequest(URL: tempUrl) }
类型转化常见的类型转化符号is : 用于判断一个实例是否是某一种类型as : 将实例转成某一种类型例子 // 1.定义数组 let array : [AnyObject]=[12, "why", 1.88] // 2.取出数组中的第一个元素 let objc=array.first! // 3.判断第一个元素是否是一个Int类型 if objc is Int { print("是Int类型") } else { print("非Int类型") } // 4.将objc转成真正的类型来使用 // 4.1.as? 将AnyObject转成可选类型,通过判断可选类型是否有值,来决定是否转化成功了 let age=objc as? Int print(age) // 结果:Optional(12) // 4.2.as! 将AnyObject转成具体的类型,但是注意:如果不是该类型,那么程序会崩溃 let age1=objc as! Int print(age1) // 结果:12
函数函数的介绍函数相当于OC中的方法
函数的格式如下
func 函数名(参数列表) -> 返回值类型 { 代码块 return 返回值 }
func是关键字,多个参数列表之间可以用逗号(,)分隔,也可以没有参数
使用箭头“->”指向返回值类型
如果函数没有返回值,返回值为Void.并且“-> 返回值类型”部分可以省略
常见的函数类型 // 1.没有参数,没用返回值 func about() -> Void { print("iphone6s plus") } // 调用函数 about() // 简单写法 // 如果没用返回值,Void可以写成() func about1() -> () { print("iphone6s plus") } // 如果没有返回值,后面的内容可以都不写 func about2() { print("iphone6s plus") } about2() // 2.有参数,没用返回值 func callPhone(phoneNum : String) { print("打电话给\(phoneNum)") } callPhone("+86 110") // 3.没用参数,有返回值 func readMessage() -> String { return "吃饭了吗?" } var str=readMessage() print(str) // 4.有参数,有返回值 func sum(num1 : Int, num2 : Int) -> Int { return num1 + num2 } var result=sum(20, num2: 30) print(result) // 5.有多个返回值的函数 let nums=[1, 3, 4, 8, 22, 23] func getNumCount(nums : [Int]) -> (oddCount : Int, evenCount : Int) { var oddCount=0 var evenCount=0 for num in nums { if num % 2==0 { oddCount++ } else { evenCount++ } } return (oddCount, evenCount) } let result=getNumCount(nums) result.oddCount result.evenCount
函数的使用注意注意一: 外部参数和内部参数
在函数内部可以看到的参数,就是内部参数在函数外面可以看到的参数,就是外部参数默认情况下,从第二个参数开始,参数名称既是内部参数也是外部参数如果第一个参数也想要有外部参数,可以设置标签:在变量名前加标签即可如果不想要外部参数,可以在参数名称前加_ // num1和a是外部参数的名称 func ride(num1 num1 : Int, a num2 : Int, b num3 : Int) -> Int { return num1 * num2 * num3 } var result1=ride(num1: 20, a: 4, b: 5) // 方法的重载:方法名称相同,但是参数不同,可以称之为方法的重载(了解) func ride(num1: Int, _ num2 :Int) -> Int { return num1 * num2 } var result2=ride(20, 20)
注意二: 默认参数
某些情况,如果没有传入具体的参数,可以使用默认参数 func makecoffee(type :String="卡布奇诺") -> String { return "制作一杯\(type)咖啡。" } let coffee1=makecoffee("拿铁") let coffee2=makecoffee()
注意三: 可变参数
swift中函数的参数个数可以变化,它可以接受不确定数量的输入类型参数它们必须具有相同的类型我们可以通过在参数类型名后面加入(...)的方式来指示这是可变参数 func sum(numbers:Double...) -> Double { var total: Double=0 for number in numbers { total +=number } return total } sum(100.0, 20, 30) sum(30, 80)
注意四: 引用类型(指针的传递)
默认情况下,函数的参数是值传递.如果想改变外面的变量,则需要传递变量的地址必须是变量,因为需要在内部改变其值Swift提供的inout关键字就可以实现对比下列两个函数 // 函数一:值传递 func swap(var a : Int, var b : Int) { let temp=a; a=b; b=temp print("a:\(a), b:\(b)") } var a=10 var b=20 swap(a, b: b) print("a:\(a), b:\(b)") // 函数二:指针的传递 func swap1(inout a : Int, inout b : Int) { let temp=a a=b b=temp print("a:\(a), b:\(b)") } swap1(&a, b: &b) print("a:\(a), b:\(b)")
函数的嵌套使用
swift中函数可以嵌套使用即函数中包含函数,但是不推荐该写法 // 函数的嵌套 let value=55 func test() { func demo() { print("demo \(value)") } print("test") demo() } demo() // 错误 test() // 执行函数会先打印'test',再打印'demo'
函数的类型函数类型的概念
每个函数都有属于自己的类型,由函数的参数类型和返回类型组成这个例子中定义了两个简单的数学函数:addTwoInts 和 multiplyTwoInts这两个函数都传入两个 Int 类型, 返回一个合适的Int值这两个函数的类型是 (Int, Int) -> Int // 定义两个函数 func addTwoInts(a : Int, b : Int) -> Int { return a + b } func multiplyTwoInt(a : Int, b : Int) -> Int { return a * b }
抽取两个函数的类型,并且使用
// 定义函数的类型 var mathFunction : (Int, Int) -> Int=addTwoInts // 使用函数的名称 mathFunction(10, 20) // 给函数的标识符赋值其他值 mathFunction=multiplyTwoInt // 使用函数的名称 mathFunction(10, 20)
函数作为方法的参数
// 3.将函数的类型作为方法的参数 func printResult(a : Int, b : Int, calculateMethod : (Int, Int) -> Int) { print(calculateMethod(a, b)) } printResult(10, b: 20, calculateMethod: addTwoInts) printResult(10, b: 20, calculateMethod: multiplyTwoInt)
函数作为方法的返回值
// 1.定义两个函数 func stepForward(num : Int) -> Int { return num + 1 } func stepBackward(num : Int) -> Int { return num - 1 } // 2.定义一个变量,希望该变量经过计算得到0 var num=-4 // 3.定义获取哪一个函数 func getOprationMethod(num : Int) -> (Int) -> Int { return num <=0 ? stepForward : stepBackward } // 4.for玄幻进行操作 while num !=0 { let oprationMethod=getOprationMethod(num) num=oprationMethod(num) print(num) }
枚举类型枚举类型的介绍概念介绍
枚举定义了一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值。在 C/OC 语言中枚举指定相关名称为一组整型值Swift 中的枚举更加灵活,不必给每一个枚举成员提供一个值.也可以提供一个值是字符串,一个字符,或是一个整型值或浮点值枚举类型的语法
使用enum关键词并且把它们的整个定义放在一对大括号内 enum SomeEnumeration { // enumeration definition goes here }
枚举类型的定义以下是指南针四个方向的一个例子
case关键词表明新的一行成员值将被定义不像 C 和 Objective-C 一样,Swift 的枚举成员在被创建时不会被赋予一个默认的整数值在上面的CompassPoints例子中,North,South,East和West不是隐式的等于0,1,2和3 enum CompassPoint { case North case South case East case West }
定义方式二:多个成员值可以出现在同一行上
enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune }
给枚举类型赋值枚举类型赋值可以是字符串/字符/整型/浮点型
注意如果有给枚举类型赋值,则必须在枚举类型后面明确说明具体的类型 // 1.枚举类型的赋值 enum CompassPoint : Int { case North=1 case South=2 case East=3 case West=4 } enum Planet { case Mercury=1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune } // 2.枚举类型的使用 let p=Planet(rawValue: 3) if let p=p { switch p { case .Mercury: print("Mercury") case .Venus: print("Venus") case .Earth: print("Mercury") case .Mars: print("Mars") case .Jupiter: print("Jupiter") case .Saturn: print("Saturn") case .Uranus: print("Uranus") case .Neptune: print("Neptune") } }
结构体结构体的介绍概念介绍
结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合结构体(struct)指的是一种数据结构结构体是值类型,在方法中传递时是值传递结构的定义格式
struct 结构体名称 { // 属性和方法 }
为什么需要结构体?先来看一个例子我们要计算平面坐标里某个点距点Center的距离是否小于200算起来很简单,勾股定理就搞定了:其中sqrt(n)用来计算n的平方根pow(x, n)用来计算x的n次方 let centerX : Double=100 let centerY : Double=100 func inRange(x : Double, y : Double) -> Bool { let disX=x - centerX let disY=y - centerX let dis=sqrt(pow(disX, 2) + pow(disY, 2)) return dis < 200 } let x : Double=100 let y : Double=1000 inRange(x, y: y)
问题
但是这样有一个不足,当我们需要比较很多个点和Center的距离的时候,这些数字并不能明确告诉我们它们代表的位置的意义,甚至我们都无法知道它们代表一个数字。如果我们可以像这样来比较位置:相比数字,它们看上去就会直观的多而这,就是我们需要自定义struct类型最直接的原因 inRange(location1) inRange(myHome)
使用结构进行改进
// 初始化结构体 struct Location { var x : Double var y : Double } // 创建结构体 let location=Location(x: 90, y: 90) // 优化刚才的方法 func inRange(location : Location) -> Bool { let disX=location.x - centerX let disY=location.y - centerY let dis=sqrt(pow(disX, 2) + pow(disY, 2)) return dis < 200 } inRange(location)
结构体的增强扩充构造函数
默认情况下创建Location时使用Location(x: x值, y: y值)但是为了让我们在使用结构体时更加的灵活,swift还可以对构造函数进行扩充扩充的注意点在扩充的构造函数中必须保证成员变量是有值的扩充的构造函数会覆盖原有的构造函数 struct Location { var x : Double var y : Double init(x : Double, y : Double) { self.x=x self.y=y } init(xyString : String) { let strs=xyString.componentsSeparatedByString(",") x=Double(strs.first!)! y=Double(strs.last!)! } } let location=Location(x: 100, y: 100) let location1=Location(xyString: "100,100")
为结构体扩充方法
为了让结构体使用更加灵活,swift的结构体中可以扩充方法例子:为了Location结构体扩充两个方法向水平方向移动的方法向垂直方向移动的方法 struct Location { var x : Double var y : Double init(x : Double, y : Double) { self.x=x self.y=y } init(xyString : String) { let strs=xyString.componentsSeparatedByString(",") x=Double(strs.first!)! y=Double(strs.last!)! } mutating func moveH(x : Double) { self.x +=x } mutating func moveV(y : Double) { self.y +=y } }
注意:
如果我们使用的Location不是自己定义的,但是我们仍旧希望在自己的项目里扩展Location的操作Swift也能帮我们达成,这个机制,叫做extension extension Location { mutating func moveH(x : Double) { self.x +=x } mutating func moveV(y : Double) { self.y +=y } }
Swift中类的使用主要内容类的介绍和定义类的属性类的构造函数一. 类的介绍和定义Swift也是一门面向对象开发的语言
面向对象的基础是类,类产生了对象
在Swift中如何定义类呢?
class是Swift中的关键字,用于定义类 class 类名 : SuperClass { // 定义属性和方法 }
注意:
定义的类,可以没有父类.那么该类是rootClass通常情况下,定义类时.继承自NSObject(非OC的NSObject)二. 如何定义类的属性类的属性介绍Swift中类的属性有多种存储属性:存储实例的常量和变量计算属性:通过某种方式计算出来的属性类属性:与整个类自身相关的属性存储属性存储属性是最简单的属性,它作为类实例的一部分,用于存储常量和变量
可以给存储属性提供一个默认值,也可以在初始化方法中对其进行初始化
下面是存储属性的写法
age和name都是存储属性,用来记录该学生的年龄和姓名chineseScore和mathScore也是存储属性,用来记录该学生的语文分数和数学分数 class Student : NSObject { // 定义属性 // 存储属性 var age : Int=0 var name : String? var chineseScore : Double=0.0 var mathScore : Double=0.0 } // 创建学生对象 let stu=Student() // 给存储属性赋值 stu.age=10 stu.name="why" stu.chineseScore=89.0 stu.mathScore=98.0
计算属性计算属性并不存储实际的值,而是提供一个getter和一个可选的setter来间接获取和设置其它属性
计算属性一般
只提供getter方法
如果只提供getter,而不提供setter,则该计算属性为只读属性,并且可以省略get{}
下面是计算属性的写法
averageScore是计算属性,通过chineseScore和mathScore计算而来的属性在setter方法中有一个newValue变量,是系统指定分配的 class Student : NSObject { // 定义属性 // 存储属性 var age : Int=0 var name : String? var chineseScore : Double=0.0 var mathScore : Double=0.0 // 计算属性 var averageScore : Double { get { return (chineseScore + mathScore) / 2 } // 没有意义,因为之后获取值时依然是计算得到的 // newValue是系统分配的变量名,内部存储着新值 set { self.averageScore=newValue } } } // 获取计算属性的值 print(stu.averageScore)
类属性类属性是与类相关联的,而不是与类的实例相关联
所有的类和实例都共有一份类属性.因此在某一处修改之后,该类属性就会被修改
类属性的设置和修改,需要通过类来完成
下面是类属性的写法
类属性使用static来修饰courseCount是类属性,用来记录学生有多少门课程 class Student : NSObject { // 定义属性 // 存储属性 var age : Int=0 var name : String? var chineseScore : Double=0.0 var mathScore : Double=0.0 // 计算属性 var averageScore : Double { get { return (chineseScore + mathScore) / 2 } // 没有意义.newValue是系统分配的变量名,内部存储着新值 set { self.averageScore=newValue } } // 类属性 static var corseCount : Int=0 } // 设置类属性的值 Student.corseCount=3 // 取出类属性的值 print(Student.corseCount)
监听属性的改变在OC中我们可以重写set方法来监听属性的改变
Swift中可以通过属性观察者来监听和响应属性值的变化
通常是监听存储属性和类属性的改变.(对于计算属性,我们不需要定义属性观察者,因为我们可以在计算属性的setter中直接观察并响应这种值的变化)
我们通过设置以下观察方法来定义观察者
willSet:在属性值被存储之前设置。此时新属性值作为一个常量参数被传入。该参数名默认为newValue,我们可以自己定义该参数名didSet:在新属性值被存储后立即调用。与willSet相同,此时传入的是属性的旧值,默认参数名为oldValuewillSet与didSet只有在属性第一次被设置时才会调用,在初始化时,不会去调用这些监听方法监听的方式如下:
监听age和name的变化 class Person : NSObject { var name : String? { // 可以给newValue自定义名称 willSet (new){ // 属性即将改变,还未改变时会调用的方法 // 在该方法中有一个默认的系统属性newValue,用于存储新值 print(name) print(new) } // 可以给oldValue自定义名称 didSet (old) { // 属性值已经改变了,会调用的方法 // 在该方法中有一个默认的系统属性oldValue,用于存储旧值 print(name) print(old) } } var age : Int=0 var height : Double=0.0 } let p : Person=Person() // 在赋值时,监听该属性的改变 // 在OC中是通过重写set方法 // 在swift中,可以给属性添加监听器 p.name="why" //p.name="yz"
类的构造函数构造函数的介绍构造函数类似于OC中的初始化方法:init方法默认情况下载创建一个类时,必然会调用一个构造函数即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数。如果是继承自NSObject,可以对父类的构造函数进行重写构造函数的基本使用构造函数的基本使用类的属性必须有值
如果不是在定义时初始化值,可以在构造函数中赋值
class Person: NSObject { var name : String var age : Int // 重写了NSObject(父类)的构造方法 override init() { name="" age=0 } } // 创建一个Person对象 let p=Person()
初始化时给属性赋值很多时候,我们在创建一个对象时就会给属性赋值
可以自定义构造函数
注意:如果自定义了构造函数,会覆盖init()方法.即不在有默认的构造函数
class Person: NSObject { var name : String var age : Int // 自定义构造函数,会覆盖init()函数 init(name : String, age : Int) { self.name=name self.age=age } } // 创建一个Person对象 let p=Person(name: "why", age: 18)
字典转模型(初始化时传入字典)真实创建对象时,更多的是将字典转成模型
注意:
去字典中取出的是NSObject,任意类型.可以通过as!转成需要的类型,再赋值(不可以直接赋值) class Person: NSObject { var name : String var age : Int // 自定义构造函数,会覆盖init()函数 init(dict : [String : NSObject]) { name=dict["name"] as! String age=dict["age"] as! Int } } // 创建一个Person对象 let dict=["name" : "why", "age" : 18] let p=Person(dict: dict)
字典转模型(利用KVC转化)利用KVC字典转模型会更加方便
注意:
KVC并不能保证会给所有的属性赋值因此属性需要有默认值基本数据类型默认值设置为0对象或者结构体类型定义为可选类型即可(可选类型没有赋值前为nil) class Person: NSObject { // 结构体或者类的类型,必须是可选类型.因为不能保证一定会赋值 var name : String? // 基本数据类型不能是可选类型,否则KVC无法转化 var age : Int=0 // 自定义构造函数,会覆盖init()函数 init(dict : [String : NSObject]) { // 必须先初始化对象 super.init() // 调用对象的KVC方法字典转模型 setValuesForKeysWithDictionary(dict) } } // 创建一个Person对象 let dict=["name" : "why", "age" : 18] let p=Person(dict: dict)
类的析构函数析构函数Swift 会自动释放不再需要的实例以释放资源
Swift 通过自动引用计数(ARC)处理实例的内存管理当引用计数为0时,系统会自动调用析构函数(不可以手动调用)通常在析构函数中释放一些资源(如移除通知等操作)析构函数的写法
deinit { // 执行析构过程 }
示例练习 class Person { var name : String var age : Int init(name : String, age : Int) { self.name=name self.age=age } deinit { print("Person-deinit") } } var p : Person?=Person(name: "why", age: 18) p=nil
自动引用计数工作机制Swift和OC一样,采用自动引用计数来管理内容当有一个强引用指向某一个动向时,该对象的引用计数会自动+1当该强引用消失时,引用计数会自动-1当引用计数为0时,该对象会被销毁循环引用在通常情况下,ARC是会自动帮助我们管理内存的
但是在开发中我们经常会出现循环引用的问题,比如下面的示例
Student对Book对象有一个强引用而Book对Student有一个强引用在两个对象都指向nil时,依然不会被销毁,就形成了循环引用 // 1.创建类 class Student { var book : Book? deinit { print("Student -- deinit") } } class Book { var owner : Student? deinit { print("Book -- deinit") } } // 2.创建对象 var stu : Student?=Student() var book : Book?=Book() // 3.相互引用 stu?.book=book book?.owner=stu // 4.对象置nil stu=nil book=nil
解决方案
swift提供了两种解决方案weak : 和OC中的__weak一样是一个弱引用.当指向的对象销毁时,会自动将指针指向nilunowned : 和OC中的__unsafe_unretained.当对象销毁时依然指向原来的位置(容易引起野指针) // 1.创建类 class Student { weak var book : Book? // unowned var book : Book=Book() deinit { print("Student -- deinit") } } class Book { var owner : Student? deinit { print("Book -- deinit") } } // 2.创建对象 var stu : Student?=Student() var book : Book?=Book() // 3.相互引用 stu?.book=book! book?.owner=stu // 4.对象置nil stu=nil book=nil
可选链可选连的概念它的可选性体现于请求或调用的目标当前可能为空(nil)如果可选的目标有值,那么调用就会成功;如果选择的目标为空(nil),则这种调用将返回空(nil)多次调用被链接在一起形成一个链,如果任何一个节点为空(nil)将导致整个链失效。可选链的使用在可选类型后面放一个问号,可以定义一个可选链。这一点很像在可选值后面放一个叹号来强制拆得其封包内的值它们的主要的区别在于当可选值为空时可选链即刻失败然而一般的强制解析将会引发运行时错误。因为可选链的结果可能为nil,可能有值.因此它的返回值是一个可选类型.可以通过判断返回是否有值来判断是否调用成功有值,说明调用成功为nil,说明调用失败可选链的示例从可选链中取值
示例描述: 人(Person)有一个狗(Dog),狗(Dog)有一个玩具(Toy),玩具有价格(price)使用代码描述上述信息 // 1.定义类 class Person { var name : String var dog : Dog? init(name : String) { self.name=name } } class Dog { var color : UIColor var toy : Toy? init(color : UIColor) { self.color=color } func runing() { print("跑起来") } } class Toy { var price : Double=0.0 } // 2.创建对象,并且设置对象之间的关系 // 2.1.创建对象 let person=Person(name: "小明") let dog=Dog(color: UIColor.yellowColor()) let toy=Toy() toy.price=100.0 // 2.2.设置对象之间的关系 person.dog=dog dog.toy=toy
需求:获取小明的大黄宠物的玩具价格
取出的值为可选类型,因为可选链中有一个可选类型为nil,则返回nil因此结果可能有值,可能为nil.因此是一个可选类型
let price=person.dog?.toy?.price print(price) // Optional(100.0)\n
需求:给小明的大黄一个新的玩具
相当于给可选类型赋值 person.dog?.toy=Toy()
需求:让小明的狗跑起来
如果可选类型有值,则会执行该方法如果可选类型为nil,则该方法不会执行 person.dog?.runing()
协议协议的格式协议的定义方式与类,结构体,枚举的定义都非常相似
protocol SomeProtocol { // 协议方法 }
遵守协议的格式
class SomeClass: SomeSuperClass, FirstProtocol, AnotherProtocol { // 类的内容 // 实现协议中的方法 }
协议的基本使用定义协议和遵守协议
// 1.定义协议 protocol SportProtocol { func playBasketball() func playFootball() } // 2.遵守协议 // 注意:默认情况下在swift中所有的协议方法都是必须实现的,如果不实现,则编译器会报错 class Person : SportProtocol { var name : String? var age : Int=0 // 实现协议中的方法 func playBasketball() { print("人在打篮球") } func playFootball() { print("人在踢足球") } }
协议之间的继承
protocol CrazySportProtocol { func jumping() } protocol SportProtocol : CrazySportProtocol { func playBasketball() func playFootball() }
代理设计模式协议继承用于代理设计模式
protocol BuyTicketProtocol { func buyTicket() } class Person { // 1.定义协议属性 var delegate : BuyTicketProtocol // 2.自定义构造函数 init (delegate : BuyTicketProtocol) { self.delegate=delegate } // 3.行为 func goToBeijing() { delegate.buyTicket() } } class HuangNiu: BuyTicketProtocol { func buyTicket() { print("买了一张火车票") } } let p=Person(delegate: HuangNiu()) p.goToBeijing()?```
协议中方法的可选 // 1.定义协议 @objc protocol SportProtocol { func playBasketball() optional func playFootball() } // 2.遵守协议 class Person : SportProtocol { var name : String? var age : Int=0 // 实现协议中的方法 @objc func playBasketball() { print("人在打篮球") } }
闭包闭包的介绍闭包和OC中的block非常相似OC中的block是匿名的函数Swift中的闭包是一个特殊的函数block和闭包都经常用于回调注意:闭包和block一样,第一次使用时可能不习惯它的语法,可以先按照使用简单的闭包,随着学习的深入,慢慢掌握其灵活的运用方法.闭包的使用block的用法回顾定义网络请求的类
@interface HttpTool : NSObject - (void)loadRequest:(void (^)())callBackBlock; @end @implementation HttpTool - (void)loadRequest:(void (^)())callBackBlock { dispatch_async(dispatch_get_global_queue(0, 0), ^{ NSLog(@"加载网络数据:%@", [NSThread currentThread]); dispatch_async(dispatch_get_main_queue(), ^{ callBackBlock(); }); }); } @end
进行网络请求,请求到数据后利用block进行回调
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self.httpTool loadRequest:^{ NSLog(@"主线程中,将数据回调.%@", [NSThread currentThread]); }]; }
block写法总结:
block的写法:类型:返回值(^block的名称)(block的参数)值:^(参数列表) { // 执行的代码};
使用闭包代替block定义网络请求的类
class HttpTool: NSObject { func loadRequest(callBack : ()->()){ dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("加载数据", [NSThread.currentThread()]) dispatch_async(dispatch_get_main_queue(), { () -> Void in callBack() }) } } }
进行网络请求,请求到数据后利用闭包进行回调
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { // 网络请求 httpTool.loadRequest ({ () -> () in print("回到主线程", NSThread.currentThread()); }) }
闭包写法总结:
闭包的写法: 类型:(形参列表)->(返回值) 技巧:初学者定义闭包类型,直接写()->().再填充参数和返回值 值: { (形参) -> 返回值类型 in // 执行代码 }
闭包的简写如果闭包没有参数,没有返回值.in和in之前的内容可以省略
httpTool.loadRequest({ print("回到主线程", NSThread.currentThread()); })
尾随闭包写法:
如果闭包是函数的最后一个参数,则可以将闭包写在()后面如果函数只有一个参数,并且这个参数是闭包,那么()可以不写 httpTool.loadRequest() { print("回到主线程", NSThread.currentThread()); } // 开发中建议该写法 httpTool.loadRequest { print("回到主线程", NSThread.currentThread()); }
闭包的循环引用如果在HttpTool中有对闭包进行强引用,则会形成循环引用
补充:在Swift中检测一个对象是否销毁,可以实现对象的deinit
函数
// 析构函数(相当于OC中dealloc方法) deinit { print("ViewController----deinit") }
循环引用的(实现)
该实现是为了产生循环引用,而产生的循环引用 class HttpTool: NSObject { // 定义属性,来强引用传入的闭包 var callBack : (()->())? func loadRequest(callBack : ()->()){ dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in print("加载数据", [NSThread.currentThread()]) dispatch_async(dispatch_get_main_queue(), { () -> Void in callBack() }) } self.callBack=callBack } }
swift中解决循环引用的方式
方案一:
使用weak,对当前控制器使用弱引用但是因为self可能有值也可能没有值,因此weakSelf是一个可选类型,在真正使用时可以对其强制解包(该处强制解包没有问题,因为控制器一定存在,否则无法调用所在函数) // 解决方案一: weak var weakSelf=self httpTool.loadData { print("加载数据完成,更新界面:", NSThread.currentThread()) weakSelf!.view.backgroundColor=UIColor.redColor() }
方案二:
和方案一类型,只是书写方式更加简单可以写在闭包中,并且在闭包中用到的self都是弱引用 httpTool.loadData {[weak self] () -> () in print("加载数据完成,更新界面:", NSThread.currentThread()) self!.view.backgroundColor=UIColor.redColor() }
方案三:(常用)
使用关键字unowned
从行为上来说 unowned 更像OC中的 unsafe_unretainedunowned 表示:即使它原来引用的对象被释放了,仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil httpTool.loadData {[unowned self] () -> () in print("加载数据完成,更新界面:", NSThread.currentThread()) self.view.backgroundColor=UIColor.redColor() }
懒加载懒加载的介绍swift中也有懒加载的方式(苹果的设计思想:希望所有的对象在使用时才真正加载到内存中)和OC不同的是swift有专门的关键字来实现懒加载lazy关键字可以用于定义某一个属性懒加载懒加载的使用格式
lazy var 变量: 类型={ 创建变量代码 }()
懒加载的使用
// 懒加载的本质是,在第一次使用的时候执行闭包,将闭包的返回值赋值给属性 // lazy的作用是只会赋值一次 lazy var array : [String]={ () -> [String] in return ["why", "lmj", "lnj"] }()
常见注释单行注释Swift 中的注释与C 语言的注释非常相似。
单行注释以双正斜杠(//)作为起始标记
// 注释内容
多行注释其起始标记为单个正斜杠后跟随一个星号(/*)
终止标记为一个星号后跟随单个正斜杠(*/)
/* 这是一个, 多行注释 */
和与 C 语言多行注释不同,Swift 的多行注释可以嵌套在其它的多行注释之中
/* 这是第一个多行注释的开头 /* 这是第二个被嵌套的多行注释 */ 这是第一个多行注释的结尾 */
文档注释Swift中添加文档注释较为简单
使用(///)可以为方法或者属性添加文档注释
/// 打电话给某人 func callPhone(phoneNum : String) { print("打电话给\(phoneNum)") }
分组注释swift中不可以再使用 #pragma mark -
如果打算对代码进行分组可以使用 // MARK:-
方式
// MARK:-
访问权限swift中的访问权限Swift 中的访问控制模型基于模块和源文件这两个概念
- internal : 在本模块中都可以进行访问- private : 在当前源文件中可以访问- public : 在其他模块中可以访问
异常处理异常的介绍只要我们在编程,就一定要面对错误处理的问题。Swift在设计的时候就尽可能让我们明确感知错误,明确处理错误比如:只有使用Optional才能处理空值;如何描述一个错误?在Swift里,任何一个遵从ErrorType protocol的类型,都可以用于描述错误。ErrorType是一个空的protocol,它唯一的功能,就是告诉Swift编译器,某个类型用来表示一个错误。通常,我们使用一个enum来定义各种错误的可能性异常的示例假如我们想要读取一个文件中的内容,按照OC的逻辑我们可以这样来模拟
当我们调用方法获取结果为nil时,你并不能确定到底参数了什么错误得到了nil func readFileContent(filePath : String) -> String? { // 1.filePath为"" if filePath=="" { return nil } // 2.filepath有值,但是没有对应的文件 if filePath !="/User/Desktop/123.plist" { return nil } // 3.取出其中的内容 return "123" } readFileContent("abc")
使用异常对上述方法进行改进
// 1.定义异常 enum FileReadError : ErrorType { case FileISNull case FileNotFound } // 2.改进方法,让方法抛出异常 func readFileContent(filePath : String) throws -> String { // 1.filePath为"" if filePath=="" { throw FileReadError.FileISNull } // 2.filepath有值,但是没有对应的文件 if filePath !="/User/Desktop/123.plist" { throw FileReadError.FileISNull } // 3.取出其中的内容 return "123" }
处理异常有三种方式
// 3.异常的处理三种方式 // 3.1.try方式,需要手动处理异常 do { let result=try readFileContent("abc") } catch { print(error) } // 3.2.try?方式,不处理异常,如果出现了异常,则返回一个nil.没有异常,则返回对应的值 // 最终返回结果为一个可选类型 let result=try? readFileContent("abc") // 3.3.try!方法,告诉系统该方法没有异常. // 注意:如果出现了异常,则程序会崩溃 try! readFileContent("abc")
Swift和OC相互调?用Swift调?用OC创建桥接?文件—> .h在桥接?文件中导?入头?文件配置桥接?文件: 项目->buildSettings —> bridging —> 配置OC调?用Swift项?目名字不能随便起Swift中的类/属性/?方法必须使?用public修饰导?项目名称-Swift.h简介
Swift 语言由苹果公司在 2014 年推出,用来撰写 OS X 和 iOS 应用程序
2014 年,在 Apple WWDC 发布
特点
从它的语法中能看到Objective-C、JavaScript、C#、Python等语言的影子
语法简单、代码简洁、使用方便
可与Objective-C混合使用(相互调用)
提供了类似 Java 的名字空间(namespace)、泛型(generic)、运算对象重载(operator overloading)
可选绑定、可选类型、类型推导
为什么设计Swift语言
让应用开发更简单、更快、更稳定
确保最终应用有着更好的质量
历史
2010 年 7 月,苹果开发者工具部门总监 Chris Lattner,开始着手 Swift 编程语言的设计工作
用一年时间,完成基本架构
Swift 大约历经 4 年的开发期,2014 年 6 月发表
Chris Lattner
克里斯·拉特纳何许人?
LLVM 项目的主要发起人与作者之一
Clang 编译器的作者
苹果公司『开发者工具』部门的主管
领导Xcode、Instruments和编译器团队
Swift的大部分基础架构均由他1人完成
评价:
大神中的大神
牛逼中的牛逼
Playground是什么?
从Xcode6开始出现(Swift开始出现)
翻译为:操场/游乐场
对于学习Swift基本语法非常方便
所见即所得(快速查看结果)
语法特性发生改变时,可以快速查看.
Swift最基本的语法变化
如果同一行有多个语句,则依然需要加
但是不建议一行多条语句
声明标识符的格式:变量/常量关键字 名称 : 数据类型
导入框架 import UIKit
定义标识符时,必须声明该标识符是变量还是常量
语句结束时不需要加;
Swift中的打印语句:print(打印的内容)
什么是常量和变量
在Swift中规定:在定义一个标识符时必须明确说明该标识符是一个常量还是变量
使用let来定义常量,定义之后不可以修改
使用var来定义变量,定义之后可以修改
常量和变量的使用注意:
注意:
是指向的对象不可以再进行修改.但是可以通过指针获得对象后,修改对象内部的属性
在真实使用过程中,建议先定义常量,如果需要修改再修改为变量(更加安全)
Swift中的类型推导
Swift是强类型的语言
Swift中任何一个标识符都有明确的类型
注意:
如果定义一个标识符时有直接进行赋值,那么标识符后面的类型可以省略.
因为Swift有类型推导,会自动根据后面的赋值来决定前面的标识符的数据类型
可以通过option+鼠标左键来查看变量的数据类型
Swift中基本运算
Swift中在进行基本运算时必须保证类型一致,否则会出错
相同类型之间才可以进行运算
因为Swift中没有隐式转换
数据类型的转化
Int类型转成Double类型:Double(标识符)
Double类型转成Int类型:Int(标识符)
分支的介绍
分支即if/switch/三目运算符等判断语句
通过分支语句可以控制程序的执行流程
if分支语句
和OC中if语句有一定的区别
不再有非0即真
必须有明确的Bool值
Bool有两个取值:false/true
判断句可以不加()
在Swift的判断句中必须有明确的真假
三目运算符
Swift中的 三目运算保持了和 OC一致的风格
guard的使用
guard是Swift2.0新增的语法
它与if语句非常类似,它设计的目的是提高程序的可读性
guard语句必须带有else语句,它的语法如下:
当条件表达式为true时候跳过else语句中的内容,执行语句组内容
条件表达式为false时候执行else语句中的内容,跳转语句一般是return、break、continue和throw
例子
switch的简单使用
基本用法和OC用法一致
不同之处:
switch后可以不跟()
case后可以不跟break(默认会有break)
一个case判断中,可以判断多个值
多个值以,隔开
简单使用补充:
如果希望出现之前的case穿透,则可以使用关键字fallthrough
switch支持多种数据类型
浮点型的switch判断
支持字符串类型
switch支持区间判断
什么是区间?
开区间:0..<10 表示:0~9,不包括10
闭区间:0...10 表示:0~10
通常我们指的是数字区间:0~10,100~200
swift中的区间常见有两种
for循环的写法
最常规写法
区间for循环
特殊写法
如果在for循环中不需要用到下标i
while和do while循环
while的判断句必须有正确的真假,没有非0即真
while后面的()可以省略
while循环
do while循环
使用repeat关键字来代替了do
字符串的介绍
OC和Swift中字符串的区别
在OC中字符串类型时NSString,在Swift中字符串类型是String
OC中字符串@"",Swift中字符串""
使用 String的原因
String是一个结构体,性能更高
NSString是一个 OC对象,性能略差
String支持直接遍历
Swift提供了 String和NSString之间的无缝转换
字符串的使用
遍历字符串
字符串拼接
两个字符串的拼接
字符串和其他数据类型的拼接
字符串的格式化
比如时间:03:04
字符串的截取
Swift中提供了特殊的截取方式
在标识符后加:as NSString即可
该方式非常麻烦
Index非常难创建
简单的方式是将String转成NSString来使用
数组的介绍
数组(Array)是一串有序的由相同类型元素构成的集合
数组中的集合元素是有序的,可以重复出现
Swift中的数组
swift字典类型是Array,是一个泛型集合
数组的初始化
数组分成:可变数组和不可变数组
使用let修饰的数组是不可变数组
使用var修饰的数组是可变数组
在声明一个Array类型的时候可以使用下列的语句之一
声明的数组需要进行初始化才能使用,数组类型往往是在声明的同时进行初始化的
对数组的基本操作
数组的遍历
数组的合并
字典的介绍
字典允许按照某个键来访问元素
字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合
键集合是不能有重复元素的,而值集合是可以重复的,键和值是成对出现的
Swift中的字典
Swift字典类型是Dictionary,也是一个泛型集合
字典的初始化
Swift中的可变和不可变字典
使用let修饰的数组是不可变字典
使用var修饰的数组是可变字典
在声明一个Dictionary类型的时候可以使用下面的语句之一
声明的字典需要进行初始化才能使用,字典类型往往是在声明的同时进行初始化的
字典的基本操作
字典的遍历
元组的介绍
元组是Swift中特有的
它是什么呢?
它是一种数据结构,在数学中应用广泛。
类似于数组或者字典
可以用于定义一组数据
元祖的定义
元祖的常见写法有两种
元祖的简单使用
可选类型的介绍
概念:
在OC开发中,如果一个变量暂停不使用,可以赋值为0(基本属性类型)或者赋值为空(对象类型)
在swift开发中,nil也是一个特殊的类型.因为和真实的类型不匹配是不能赋值的(swift是强语言)
但是开发中赋值nil,在所难免.因此推出了可选类型
可选类型的取值:
空值
有值
定义可选类型
定义一个可选类型有两种写法
最基本的写法
语法糖(常用)
可选类型的使用
真实应用场景
目的:让代码更加严谨(可选绑定)
函数的介绍
函数相当于OC中的方法
函数的格式如下
func是关键字,多个参数列表之间可以用逗号(,)分隔,也可以没有参数
使用箭头“->”指向返回值类型
如果函数没有返回值,返回值为Void.并且“-> 返回值类型”部分可以省略
常见的函数类型
函数的使用注意
注意一: 外部参数和内部参数
在函数内部可以看到的参数,就是内部参数
在函数外面可以看到的参数,就是外部参数
默认情况下,从第二个参数开始,参数名称既是内部参数也是外部参数
如果第一个参数也想要有外部参数,可以设置标签:在变量名前加标签即可
如果不想要外部参数,可以在参数名称前加_
注意二: 默认参数
某些情况,如果没有传入具体的参数,可以使用默认参数
注意三: 可变参数
swift中函数的参数个数可以变化,它可以接受不确定数量的输入类型参数
它们必须具有相同的类型
我们可以通过在参数类型名后面加入(...)的方式来指示这是可变参数
注意四: 引用类型(指针的传递)
默认情况下,函数的参数是值传递.如果想改变外面的变量,则需要传递变量的地址
必须是变量,因为需要在内部改变其值
Swift提供的inout关键字就可以实现
对比下列两个函数
函数的嵌套使用(了解即可)
swift中函数可以嵌套使用
即函数中包含函数,但是不推荐该写法
类的介绍
Swift也是一门面向对象开发的语言
面向对象的基础是类,类产生了对象
在Swift中如何定义类呢?
class是Swift中的关键字,用于定义类
注意:
定义的类,可以没有父类.那么该类是rootClass
通常情况下,定义类时.继承自NSObject(非OC的NSObject)
如何定义类的属性
Swift中类的属性有多种
存储属性:存储实例的常量和变量
计算属性:通过某种方式计算出来的属性
类属性:与整个类自身相关的属性
存储属性
age和name都是存储属性,用来记录该学生的年龄和姓名
chineseScore和mathScore也是存储属性,用来记录该学生的语文分数和数学分数
存储属性是最简单的属性,它作为类实例的一部分,用于存储常量和变量
可以给存储属性提供一个默认值,也可以在初始化方法中对其进行初始化
下面是存储属性的写法
计算属性
计算属性并不存储实际的值,而是提供一个getter和一个可选的setter来间接获取和其它设置属性
存储属性一般只提供getter方法
如果只提供getter,而不提供setter,则该计算属性为只读属性,并且可以省略get{}
下面是计算属性的写法
averageScore是计算属性,通过chineseScore和mathScore计算而来的属性
在setter方法中有一个newValue变量,是系统指定分配的
类属性
类属性是与类相关联的,而不是与类的实例相关联
所有的类和实例都共有一份类属性.因此在某一处修改之后,该类属性就会被修改
类属性的设置和修改,需要通过类来完成
下面是类属性的写法
类属性使用static来修饰
例:courseCount是类属性,用来记录学生有多少门课程
监听属性的改变
在OC中我们可以重写set方法来监听属性的改变
Swift中可以通过属性观察者来监听和响应属性值的变化
通常是监听存储属性和类属性的改变.(对于计算属性,我们不需要定义属性观察者,因为我们可以在计算属性的setter中直接观察并响应这种值的变化)
我们通过设置以下观察方法来定义观察者
监听age和name的变化
willSet:在属性值被存储之前设置。此时新属性值作为一个常量参数被传入。该参数名默认为newValue,我们可以自己定义该参数名
didSet:在新属性值被存储后立即调用。与willSet相同,此时传入的是属性的旧值,默认参数名为oldValue
willSet与didSet只有在属性第一次被设置时才会调用,在初始化时,不会去调用这些监听方法
监听的方式如下:
构造函数的介绍
构造函数类似于OC中的初始化方法:init方法
默认情况下载创建一个类时,必然会调用一个构造函数
即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数。
如果是继承自NSObject,可以对父类的构造函数进行重写
构造函数的基本使用
类的属性必须有值
如果不是在定义时初始化值,可以在构造函数中赋值
初始化时给属性赋值
很多时候,我们在创建一个对象时就会给属性赋值
可以自定义构造函数
注意:如果自定义了构造函数,会覆盖init()方法,即不在有默认的构造函数
字典转模型(初始化时传入字典)
真实创建对象时,更多的是将字典转成模型
注意:
去字典中取出的是NSObject,任意类型
可以通过as!转成需要的类型,再赋值(不可以直接赋值)
字典转模型(利用KVC转化)
利用KVC字典转模型会更加方便
注意:
KVC并不能保证会给所有的属性赋值
因此属性需要有默认值
基本数据类型默认值设置为0
对象或者结构体类型定义为可选类型即可(可选类型没有赋值前为nil)
闭包的介绍
闭包和OC中的block非常相似
OC中的block是匿名的函数
Swift中的闭包是一个特殊的函数
block和闭包都经常用于回调
闭包的使用
block的用法回顾
定义网络请求的类
进行网络请求,请求到数据后利用block进行回调
block写法总结:
block的写法: 类型: 返回值(^block的名称)(block的参数)
使用闭包代替block
定义网络请求的类
进行网络请求,请求到数据后利用闭包进行回调
闭包写法总结:
闭包的简写
如果闭包没有参数,没有返回值.in和in之前的内容可以省略
尾随闭包写法:
如果闭包是函数的最后一个参数,则可以将闭包写在()后面
如果函数只有一个参数,并且这个参数是闭包,那么()可以不写
闭包的循环引用
如果在HttpTool中有对闭包进行强引用,则会形成循环引用
swift中解决循环引用的方式
懒加载的介绍
swift中也有懒加载的方式
(苹果的设计思想:希望所有的对象在使用时才真正加载到内存中)
和OC不同的是swift有专门的关键字来实现懒加载
lazy关键字可以用于定义某一个属性懒加载
懒加载的使用
格式
懒加载的使用
上一篇:Gmail打不开怎么解决
下一篇:“必须”的近义词是什么?
发表评论