目前随着公司开发模式的变更,swift也显得越发重要,相对来说,swift语言更加简洁,严谨.但对于我来说,感觉swift细节的处理很繁琐,可能是还没适应的缘故吧.基本每写一句代码,都要对变量的数据类型进行判断,还要进行强转等等.
好了,废话不多说了,直接把我对swift的语法的一些理解奉献给大家,希望能对学习swift语法的朋友有所帮助,如有不足之处,还请多多包涵,如果有错误之处,欢迎指正
Swift 介绍
简介
Swift 语言由苹果公司在 2014 年推出,用来撰写 OS X 和 iOS 应用程序
2014 年,在 Apple WWDC 发布
历史
2010 年 7 月,苹果开发者工具部门总监
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初体验
Playground是什么?
从Xcode6开始出现(Swift开始出现)
翻译为:操场/游乐场
对于学习Swift基本语法非常方便
所见即所得(快速查看结果)
语法特性发生改变时,可以快速查看.
一.Swift最基本的语法变化
1.导入框架
1 OC: #import
2 Swift: import UIKit
2.定义标识符
OC: int a = 20;
Swift: let a : Int = 20 == let a = 20
定义标识符格式: let / var 标识符 : 数据类型 = 赋值
注意:let声明的是常量,不可以对常量重新赋值
Swift中定义标识符,必须声明该标识符是变量(var)还是常量(let)
注意:在swift中如果一行代码中只有一条语句,那么语句后面的 ;(分号) 可以省略
一行内有多条语句 ; 不可以省略, 不建议一行写多条语句
3.Swift中的打印
1 OC: NSLog(@"Hello world”); / NSLog(@"%d", a);
2 //Swift中字符串不需要@
3 print(a) / print("hello world")
二.常量&变量
1.什么是常量和变量?
在Swift中规定:在定义一个标识符时,必须明确说明该标识符是常量还是变量
使用let来定义常量,定义之后,不能进行修改
使用var来定义变量,定义之后,可以进行修改
2.常量个变量的使用注意
在使用中,建议先使用常量,这样更安全,防止不小心修改之前的值
如果需要修改时,再把常量修改为变量
注意:常量的本质是,指向的内存地址不能修改,但可以找到内存地址对应的对象,修改对象内部的属性
1 let view : UIView = UIView()
2 view.alpha = 0.5
3 view.backgroundColor = UIColor.orangeColor()
三.类型推导
1.什么是类型推导?
在Swift中,如果在定义标识符的同时直接对其进行赋值,那么系统会自动根据赋的值的数据类型,推导出标识符的类型
如果定义标识符的同时直接赋值,那么标识符后面的数据类型可以省略
可以通过option + 鼠标左键来查看标识符的类型
1 let n = 3.14
2 let View = UIView()
四.Swift中的基本运算
1.swift中在进行基本运算时,必须保证两个参与运算的值得数据类型一致,否则会报错
因为swift中没有隐式转换
1 let m = 20
2 let n = 3.44
3 // let result = m + n 错误写法
2.数据类型的转化
将Int 转换为 Double Double(m)
将Double 转换为 Int Int(n)
1 let a : Double = 2.44
2 let b : CGFloat = 4.55
3 let result1 = a + Double(b)
五.逻辑分支
1.什么是逻辑分支?
分支就是if / witch / 三目运算符 等判断语句
通过分支语句可以控制程序的执行流程
2.if分支语句
OC中if的写法 : BOOL --> YES/NO
1 int a = 20
2 if (a > 0) {
3 NSLog(@"a大于0")
4 }
5
6 if (a) {
7 NSLog(@"a不等于0")
8 }
Swift和OC的差异
1. if后面的()可以省略掉
2. swift中没有非0(nil)即真 Bool --> true/false
1 let a = 20
2 if a > 0 {
3 print("a大于0")
4 } else {
5 print("a不大于0")
6 }
7
3.三目运算符
swift中的三目运算符合OC没什么差别
let result = m > n ? m : n
4.guard的使用
4.1 guard是Swift2.0新增的语法
4.2 它与if语句非常类似,它设计的目的是提高程序的可读性
4.3 guard语句必须带有else语句,它的语法如下:
4.3.1当条件表达式为true时候跳过else语句中的内容,执行语句组内容
4.3.2条件表达式为false时候执行else语句中的内容,跳转语句一般是return、break、continue和throw
1 func online(age : Int , IDCard : Bool , money : Int) {
2 guard age >= 18 else {
3 print("回家叫家长")
4 return
5 }
6 guard IDCard == true else {
7 print("回家拿身份证")
8 return
9 }
10 guard money >= 5 else {
11 print("回家拿钱")
12 return
13 }
14 print("留下来上网")
15 }
16 online(19, IDCard: true, money: 4)
5.switch分支
5.1苹果在swift中对swift中对switch进行了很大的加强
5.2 Swift中switch和OC中switch的差异
switch中后面的()可以省略
case结束之后可以不加break,也不会产生case穿透
补充:如果希望产生case穿透,需要在语句结束之后加上fallthrough
在swift中switch的case后面可以跟上多个条件, 并且多个条件以 , 分割
1 switch sex {
2 case 0, 1:
3 print("正常")
4 default:
5 print("非正常人")
6 }
5.3 swift支持多种数据类型判断
1 //浮点型switch判断
2 switch m {
3 case 3.14:
4 print("m是π")
5 default:
6 print("m非π")
7 }
8
9 //字符串switch判断
10 switch opration {
11 case "+":
12 result = a + b
13 case "-":
14 result = a - b
15 case "*":
16 result = a * b
17 case "/":
18 result = a / b
19 default:
20 print("非法操作")
21 }
22
判断区间类型
什么是区间?
通常我们指的是数字区间:0~10,100~200
swift中的区间常见有两种
半开半闭区间:0..<10 表示:0~9,不包括10
闭区间:0...10 表示:0~10
1 let score = 92
2
3 switch score {
4 case 0..<60:
5 print("不及格")
6 case 60..<80:
7 print("及格")
8 case 80..<90:
9 print("良好")
10 case 90...100:
11 print("优秀")
12 default:
13 print("不合理分数")
14 }
15
六.循环
常见的循环有:for/while/do while
1.for循环
1.1 OC中的for循环写法
1 for (int i = 0; i < 10; i++) {
2
3 }
1.2 swift中的写法
1 // 区间遍历 0..<10 0...9
2 for i in 0..<10 {
3 print(i)
4 }
5
6 for i in 0...9 {
7 print(i)
8 }
9
10 // 如果一个标识符不需要使用, 那么可以通过 _ 来代替
11 for _ in 0..<10 {
12 print("hello world")
13 }
2.while循环
2.1 OC中的写法
2.2 swift中的写法
2.2.1while后面的()可以省略
2.2.2没有非0(nil)即真
1 var i = 10
2 while i > 0 {
3 print(i)
4 i -= 1
5 }
3.do while循环
1 // 区别: 不再使用do while --> repeat while
2 var m = 0
3 repeat {
4 print(m)
5 m += 1
6 } while m < 10
七.字符串
1.字符串的介绍
1.2OC和Swift中字符串的区别
在OC中字符串类型时NSString,在Swift中字符串类型是String
OC中字符串@"",Swift中字符串""
1.3使用 String 的原因
String 是一个结构体,性能更高
NSString 是一个 OC 对象,性能略差
String 支持直接遍历
String 提供了 String 和 NSString之间的无缝转换
2.字符串的定义
2.1定义不可变字符串
2.2定义可变字符串
var strM = "hello world"
strM = "hello china"
3.获取字符串的长度
先获取字符集合,再获取集合的count属性
let length = str.characters.count
4.遍历字符串
for c in str.characters {
print(c)
}
5.字符串的拼接
5.1字符串之间的拼接
let str1 = "Hello"
let str2 = "World"
let str3 = str1 + str2
5.2字符串和其它标识符间的拼接
let name = "lgp"
let age = 18
let height = 1.98
let infoStr = "my name is \(name), age is \(age), height is \(height)"
5.3字符串格式化
比如时间:03:04 如果显示 3 : 4 就不好.所以需要格式化
let min = 3
let second = 4
let timeStr = String(format: "%02d:%02d", arguments: [min, second])
6.字符串的截取
6.1简单的方式是将String转成NSString来使用
在标识符后加:as NSString即可
1 // 1.方式一: 将String类型转成NSString类型, 再进行截取
2 // (urlString as NSString) --> NSString
3 let header = (urlString as NSString).substringToIndex(3)
4 let footer = (urlString as NSString).substringFromIndex(10)
5 let range = NSMakeRange(4, 5)
6 let middle = (urlString as NSString).substringWithRange(range)
6.1Swift中提供了特殊的截取方式
该方式非常麻烦
Index创建较为麻烦
1 // 2.方式二: Swift原生方式进行截取
2 let headerIndex = urlString.startIndex.advancedBy(3)
3 let header1 = urlString.substringToIndex(headerIndex)
4
5 let footerIndex = urlString.endIndex.advancedBy(-3)
6 let footer1 = urlString.substringFromIndex(footerIndex)
7
8 let range1 = headerIndex.advancedBy(1)..1)
9 let middle1 = urlString.substringWithRange(range1)
八.数组的使用
1.数组的介绍
1.1 数组(Array)是一串有序的由相同类型元素构成的集合
1.2 数组中的集合元素是有序的,可以重复出现
1.3 Swift中的数组
swift数组类型是Array,是一个泛型集合
2.数组的初始化
2.1 定义不可变数组,使用let修饰
注意:不可变数组要在定义的同时初始化,否则没有意义
let array = ["why", "yz"]
2.2 定义可变数组,使用var修饰
注意:数组是泛型集合,必须确定该数组中存放元素的类型
//基本写法
var arrayM = Array()
//单写法
var arrayM = [String]()
3.对可变数组的基本操作(增删改查)
3.1 添加元素
3.2 删除元素
let removeItem = arrayM.removeAtIndex(1) 返回值为删除的元素
arrayM.removeAll()
3.3 修改元素
3.4 查找元素(根据下标获取元素)
4.数组的遍历
4.1 遍历下标值
1 for i in 0..<array.count {
2 print(array[i])
3 }
4.2遍历元素
for name in array {
print(name)
}
4.3遍历下标值和元素
1 for (index, name) in array.enumerate() {
2 print(index)
3 print(name)
4 }
5.数组的合并
相同类型的数组可以相加进行合并
可变数组和不可变的数组也能合并
1 let array1 = ["why", "yz"]
2 let array2 = ["lmj", "lnj"]
3 let resultArray = array1 + array2
九.字典的使用
1.字典的介绍
1.1字典允许按照某个键来访问元素
1.2字典是由两部分集合构成的,一个是键(key)集合,一个是值(value)集合
1.3键集合是不能有重复元素的,而值集合是可以重复的,键和值是成对出现的
1.4Swift中的字典
Swift字典类型是Dictionary,也是一个泛型集合
2.字典的初始化
2.1 定义不可变字典,使用let修饰
注意:不可变字典要在定义的同时初始化,否则没有意义
系统会根据[]中存放的是键值对,还是一个个元素,来判断该[]是一个数组还是字典
let dict = ["name" : "why", "age" : 18, "height" : 1.88]
2.2 定义可变字典,使用var修饰
注意:字典是泛型集合,必须制定该数组中存放元素的类型
基本写法
简单写法
var dictM = [String : NSObject]() // 常见
3.对可变字典的基本操作(增删改查)
3.1 添加元素
dictM.updateValue("why", forKey: "name")
3.2 删除元素
1 dictM.removeValueForKey("age")
3.3 修改元素
1 //如果原有没有对应的key/value, 那么就添加键值对
2 // 如果原有已经有对应的key/value, 那么直接修改
3 dictM.updateValue("1.77", forKey: "height")
4 dictM["name"] = "why"
3.4 查找元素(获取元素)
1 let item = dictM["name"]
4.字典的遍历
4.1 遍历字典中所有的key
1 for key in dict.keys {
2 print(key)
3 }
4.2 遍历字典中所有的value
1 for value in dict.values {
2 print(value)
3 }
4.3 遍历字典中所有的key / value
1 for (key, value) in dict {
2 print(key)
3 print(value)
4 }
5.字典的合并
相同类型的字典也不可以相加进行合并
可以把其中一个字典改为可变的,遍历不可变得字典,把元素一个一个的添加到另一个不可变字典中
1 let dict1 = ["name" : "why", "age" : 18]
2 var dict2 = ["height" : 1.88, "phoneNum" : "+86 110"]
3
4 for (key, value) in dict1 {
5 dict2[key] = value
6 }
7
十.元组的使用
1.元组的介绍
1.1元组是Swift中特有的,OC中并没有相关类型
1.2它是什么呢?
1.2.1 它是一种数据结构,在数学中应用广泛
1.2.2 类似于数组或者字典
1.2.3 可以用于定义一组数据
1.2.4 组成元组类型的数据可以称为“元素”
2.为什么使用元组?
如果字典或数组保存多种数据类型,那么从字典会数组取出来的数据类型是NSObject,我们使用的时候很不方便,要先转换为真实类型
元组保存多种数据类型,取出来就是该数据的真实类型,不需要转换就能直接使用
3.元组的定义
1 let infoTuple = ("why", 18, 1.88, "+86 110")
2 // 使用元组描述一个人的信息
3 ("1001", "张三", 30, 90)
4 // 给元素加上元素名称,之后可以通过元素名称访问元素
5 (id:"1001", name:"张三", english_score:30, chinese_score:90)
前言:swift语法基础篇(二)来了,想学习swift的朋友可以拿去参考哦,有兴趣可以相互探讨,共同学习哦.
一.可选类型(重点内容)
1.什么是可选类型?
1.1在OC开发中,如果一个变量暂停不使用,可以赋值为0(基本属性类型)或者赋值为空(对象类型)
1.2在swift开发中,nil也是一个特殊的类型.因为和真实的类型不匹配是不能赋值的(swift是强类型语言)
1.3但是开发中赋值nil,在所难免.因此推出了可选类型
目的:让代码更加严谨
2.可选类型的取值
可选类型要么是:空值 , 要么是:有值
只有为可选类型,才能赋值为nil
3.定义可选类型
3.1 普通写法
var name : Optional = nil
3.2 简单写法(语法糖)
4.给可选类型赋值
4.1 普通赋值
4.2 直接赋值
name = "why" // 系统会对字符串进行包装Optional, 再进行赋值
5.强制解包(取出可选类型中具体的值)
5.1 为什么要强制解包
可选类型的值的格式为: Optional("why") 我们要想使用其真实值,必须要解包
5.2 怎么解包?
在可选类型的标识符后面加!
注意:解包前,要先判断可选类型是否为nil , 如果为nil,强制解包会报错
6.可选绑定
1 if let name = name {
2 print(name)
3 print(name)
4 }
6.1 系统先判断可选类型是否为nil,如果为nil,就跳过{}中的内容
6.2 如果有值,会先对name进行强制解包,然后把解包结果赋值给name
7.可选类型的应用场景
可选类型能让代码变得更加严谨
类型转换后的数据类型一般都为可选类型,因为转换不成功就为nil , 只有可选类型能接收nil
7.1字符串类型转Int类型
可以看到,类型转换后的类型为可选类型
使用转换后的结果的时候,一定要先判断是否为nil, 如果为nil, 使用会报错
7.2 根据string创建一个NSURL
1 let urlString = "www.baidu.com"
2
3 let url : NSURL? = NSURL(string: urlString)
4 if let url = url {
5 let request = NSURLRequest(URL: url)
6 }
if let url = url 内部做了以下判断:
1.判断url是否为nil,为nil 就跳过{}中的内容
2.不为nil,就对url进行强制解包
3.将解包后的结果赋值给前面的url
7.3 根据一个plist文件创建一个数组
1 let path = NSBundle.mainBundle().pathForResource("123.plist", ofType: nil)
2
3 if let path = path {
4 NSArray(contentsOfFile:path)
5 }
二.类型转化
1.is的使用:判断是否是某种类型
1 //1.is的使用
2 let infoArray = ["why" , 18 , 1.98]
3 let item = infoArray[1]
4
5 //item.isKindOfClass(UIButton.self)
6
7 //string是结构体,不能用isKindOfClass
8 if item is String {
9 print("是字符串")
10 }else {
11 print("不是字符串")
12 }
2.as的使用
2.1 as直接使用: swift类型和oc类型的转化
1 let urlString = "www.baidu.com"
2 (urlString as NSString).substringToIndex(3)
2.2 as? 的使用: 将NSObject转成某一确定类型的可选类型
1 let item1 = infoArray[0]
2 let name = item1 as? String
3 if let name = name {
4 print(name.characters.count)
5 }
6 简写:
7 if let name = infoArray[0] as? String {
8 print(name.characters.count)
9 }
2.3 as! 的使用: 将NSObject转成确定的类型,但如果转化不成功,则程序会崩溃
1 let count = (infoArray[0] as! String).characters.count
三.函数
1.函数的介绍
1.1 函数相当于OC中的方法
1.2 函数的格式如下
func 函数名(参数列表) -> 返回值类型 {
代码块
return 返回值
}
1.3 func是关键字,多个参数列表之间可以用逗号(,)分隔,也可以没有参数
1.4 使用箭头“->”指向返回值类型
1.5 如果函数没有返回值,返回值为Void.并且“-> 返回值类型”部分可以省略
2.常见的函数类型
3.内部参数和外部参数
3.1 什么是内部参数
3.11 在函数内部就可以看到的参数(标识符)就是内部参数
3.12 默认所有的参数都是内部参数
3.2 什么是外部参数
3.21 在函数外部就可以看到的参数(标识符)就是外部参数
3.22 默认从第二个参数开始都是外部参数
3.23 如果想让第一个参数成为外部参数,可以设置标签:在变量名前加标签即可
3.24 如果不想要外部参数,可以在参数名称前加_ (_ 和参数名称中间要加一个 空格)
3.25 也可以给外部参数设置标签 ,相当于给外部参数起别名
4.默认参数
4.1 什么是默认参数?
如果一个函数需要参数,而我们调用的时候又不想传参,那么在设计函数的时候,可以给函数一个默认的参数
如果调用函数,不传参数,就按照默认的参数对函数进行处理
5.可变参数
5.1 swift中函数的参数个数可以变化,它可以接收不确定数量的输入类型参数
5.2 它们必须具有相同的类型
5.3 我们可以通过在参数类型名后面加入(...)的方式来指示这是可变参数
作用:方便需求变化时,更改代码,当参数个数需求变更或很多时,可以轻松些代码
6.指针参数
6.1 默认情况下,函数的参数是值传递.如果想改变外面的变量,则需要传递变量的地址
6.2 必须是变量,因为需要在内部改变其值
6.3 Swift提供的inout关键字就可以实现
7.函数的嵌套
swift中函数是可以嵌套的,即函数中包含函数,但是不推荐该写法
OC中方法不可以嵌套
1 // 函数的嵌套
2 let value = 55
3 func test() {
4 func demo() {
5 print("demo \(value)")
6 }
7 print("test")
8 demo()
9 }
10 demo() // 错误 必须在对应的作用域内调用
11 test() // 执行函数会先打印'test',再打印'demo'
8.函数的类型
8.1什么是函数的类型?
每个函数都有自己的类型, 函数的类型由 函数的参数类型和返回值类型组成
1 // 定义两个函数
2 func addTwoInts(a : Int, b : Int) -> Int {
3 return a + b
4 }
5
6 func multiplyTwoInt(a : Int, b : Int) -> Int {
7 return a * b
8 }
9
这两个函数的类型是 (Int, Int) -> Int
8.2抽取两个函数的类型,并且使用
1 // 定义函数的类型
2 var mathFunction : (Int, Int) -> Int = addTwoInts
3
4 // 使用函数的名称
5 mathFunction(10, 20)
6
7 // 给函数的标识符赋值其他值
8 mathFunction = multiplyTwoInt
9
10 // 使用函数的名称
11 mathFunction(10, 20)
8.3 函数作为方法的参数
1 // 3.将函数的类型作为方法的参数
2 func printResult(a : Int, b : Int, calculateMethod : (Int, Int) -> Int) {
3 print(calculateMethod(a, b))
4 }
5
6 printResult(10, b: 20, calculateMethod: addTwoInts)
7 printResult(10, b: 20, calculateMethod: multiplyTwoInt)
8.4函数作为方法的返回值
1 // 1.定义两个函数
2 func stepForward(num : Int) -> Int {
3 return num + 1
4 }
5
6 func stepBackward(num : Int) -> Int {
7 return num - 1
8 }
9
10 // 2.定义一个变量,希望该变量经过计算得到0
11 var num = -4
12
13 // 3.定义获取哪一个函数
14 func getOprationMethod(num : Int) -> (Int) -> Int {
15 return num <= 0 ? stepForward : stepBackward
16 }
17
18 // 4.for循环进行操作
19 while num != 0 {
20 let oprationMethod = getOprationMethod(num)
21 num = oprationMethod(num)
22 print(num)
23 }
四.枚举类型
1.什么是枚举?
1.1 枚举是一种数据类型,枚举是一组具有共同特性的数据的集合
1.2 枚举可以让我们更安全的使用数据
1.3 oc中只能对枚举成员赋值为整型
1.4 swift中的枚举更加灵活,可以给每一枚举成员赋值,这些值可以为字符,字符串,整型,浮点型等
2.枚举类型的定义
2.1 使用enum关键词,把枚举定义在一个大括号内
1 enum <#name#> {
2 case <#case#>
3 }
2.2 case关键词表明新的一行成员值将被定义
2.3 不像 C 和 Objective-C 一样,Swift 的枚举成员在被创建时不会被赋予一个默认的整数值 (0.1.2.3...)
2.4 定义方式二: 多个成员值可以写在同一行
1 enum Planet {
2 case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
3 }
3.枚举类型的使用
1 enum Direction : Int{
2 case East = 1 , West , North , Sourth
3 }
4 //完整写法
5 let d : Direction = Direction.North
6 //简单写法:根据上下文能推导出确定的类型
7 var d1 = Direction.East
8 d1 = .West
9
10 //枚举类型的使用
11 let btn = UIButton(type: .Custom)
4.给枚举类型赋值
4.1 枚举类型赋值可以是字符串/字符/整型/浮点型
4.2 注意: 如果给枚举类型赋值, 则必须在枚举类型后面说明赋值的类型
4.3 给枚举类型赋的值的类型,必须跟说明的类型一致,否则会报错
1 let btn = UIButton(type: .Custom)
2
3 enum Direction : String{
4 case East = "1"
5 case West = "3"
6 case North = "6"
7 case Sourth = "9"
8 }
9 var b : Direction = .West
10
11 let a = Direction(rawValue: “6”)
注意: 通过rawValue:方式取出来的值的类型 为 对应类型的 可选类型
因为通过这种方法不一定能取出来值,可能为nil 所以为可选类型 比较严谨
4.4给枚举类型赋值方式二
1 enum Direction2 : Int{
2 case East = 1 , West , North , Sourth
3 //只要给第一个成员赋值,会自动按照递增的方式给后面的成员赋值
4 //相当于 West = 2, North = 3, Sourth = 4
5 //注意:这种赋值方法只对整型有效,赋值其它类型无效
五.结构体
1.什么是结构体?
1.1结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合
1.2结构体(struct)指的是一种数据结构
1.3结构体是值类型,在方法中传递时是值传递
2.结构的定义格式
struct 结构体名称 {
// 属性和方法
}
3.在swift中对结构体进行了很大的增强
3.1 扩充构造函数
3.11 默认情况下,创建Location 只能使用Location (x: Double , y : Double) 方法创建
3.12 但为了让结构体的使用更加灵活, swift中,可以对其构造方法就行扩充
3.13 注意: 结构体中值必须为可变的var ,否则没有意义
3.2 为结构体扩充方法
六.类
1.类的介绍和定义
1.1 Swift也是一门面向对象开发的语言,面向对象的基础是类,类产生了对象
1.2 在swift中如何定义类?
class是Swift中的关键字,用于定义类
1.3 定义的类,可以没有父类.那么该类是rootClass
1.4 通常情况下,定义类时.继承自NSObject
1 class 类名 : SuperClass {
2 // 定义属性和方法
3 }
4 class Person {
5 var name : String = ""
6 var age : Int = 0
7 }
8 let p = Person()
9 p.name = "lkj"
10 p.age = 18
2.类的属性定义
2.1类的属性介绍:Swift中类的属性有多种
存储属性:存储实例的常量和变量
计算属性:通过某种方式计算出来的属性
类属性:与整个类自身相关的属性
3.监听属性的改变
3.1 在OC中我们可以重写set方法来监听属性的改变 (kvc监听系统属性的改变)
3.2 Swift中可以通过属性观察者来监听和响应属性值的变化
3.3 通常是监听存储属性和类属性的改变.(对于计算属性不需要定义属性观察者,因为可以在计算属性的set方法中直接观察)
3.4 怎么监听?
通过willSet 和didSet两个方法来监听 , 统称为属性监听器
4.类的构造函数
4.1 构造函数类似于OC中的初始化方法: init方法
4.2 创建一个类,系统会默认提供一个构造函数
4.3 自定义构造函数 , 一般用来初始化时给属性赋值
注意:如果自定义构造函数,会覆盖系统默认提供的构造函数 , 如果想保留,需要重写
1 class Person {
2 var name : String
3 var age : Int
4 // 自定义构造函数,会覆盖init()函数
5 init(name : String, age : Int) {
6 // 如果在一个方法中, 属性名称产生了歧义(重名), self.不可以省略
7 self.name = name
8 self.age = age
9 }
10 }
11 // 创建一个Person对象
12 let p = Person(name: "why", age: 18)
13
14
15 class Person: NSObject {
16 var name : String
17 var age : Int
18 // 重写了NSObject(父类)的构造方法 在init前面加上override
19 override init() {
20 name = ""
21 age = 0
22 }
23 }
24 // 创建一个Person对象
25 let p = Person()
5.字典转模型
5.1 使用kvc的条件?
5.11 必须继承自NSObject
5.12 在构造函数中使用,必须先调用super.init()
5.2 利用kvc字典转模型非常方便
5.3 使用kvc注意点
5.31 属性需要有默认的值
5.32 基本数据类型默认值一般设置为0
5.33 对象或结构体类型定义为可选类型(可选类型没有赋值前为nil)
1 class Person: NSObject {
2 // 结构体或者类的类型,必须是可选类型.因为不能保证一定会赋值
3 var name : String?
4 // 基本数据类型不能是可选类型,否则KVC无法转化
5 var age : Int = 0
6 // 自定义构造函数,会覆盖init()函数
7 init(dict : [String : NSObject]) {
8 // 必须先初始化对象
9 super.init()
10 // 调用对象的KVC方法字典转模型
11 setValuesForKeysWithDictionary(dict)
12 }
13 //如果字典中某些键值对,在类中找不到对应的属性,就会报错
14 //不想让它报错,可以重写setValue forUndefinedKey key:
15 override func setValue(value: AnyObject?, forUndefinedKey key: String) {
16 }
17 }
18 // 创建一个Person对象
19 let dict = ["name" : "why", "age" : 18]
20 let p = Person(dict: dict)
6.析构函数
6.1 swift会自动释放不需要的实例以释放资源
6.11 swift 通过ARC 处理实例的内存管理
6.12 当引用计数为0时,系统会自动调用析构函数(不可以手动调用)
6.13 通常在析构函数中释放一些资源(如:移除通知等操作)
6.2 析构函数的写法
1 deinit {
2 // 执行析构过程
3 }
6.21 示例练习
1 class Person {
2 var name : String
3 var age : Int
4
5 init(name : String, age : Int) {
6 self.name = name
7 self.age = age
8 }
9
10 deinit {
11 print("Person-deinit")
12 }
13 }
14
15 var p : Person? = Person(name: "why", age: 18)
16 p = nil
前言:swift语法基础篇(二)来了,想学习swift的朋友可以拿去参考哦,有兴趣可以相互探讨,共同学习哦.
一.自动引用计数
1.自动引用计数工作机制
1.1 swift和oc一样,采用自动引用计数来管理内存
1.2 当有强引用指向对象,对象的引用计数 +1 , 强引用消失,自动计数 -1
1.3 如果对象的引用计数为0 , 那么该对象会被销毁
2.循环引用
2.1 什么是循环引用?
两个(或多个)对象互相强引用
2.2 循环引用对项目有什么影响
循环引用会让对象不会被销毁,一直保存在内存中,可能导致项目运行不畅
2.3 怎么解决强引用问题?
只需要让其中一个对象对另外一个对象的引用变为弱引用即可
在swift中用waek 相当于OC中的 __weak ,或者使用 unowned 相当于OC中的 __unsafe_unretained
3.weak 和 unowned的区别
3.1 相同点:
都是一个弱引用,不会对对象进行retain
3.2 不同点
3.21 weak(__weak) :当弱引用指向的对象销毁时,该引用会指向nil 所以用weak指向的数据类型为可选类型
3.22 unowned(__unsafe_unretained) :当弱引用指向的对象销毁时,依然指向原来的内存地址, 容易产生错误(野指针/访问僵尸对象)
3.23 unowned不支持可选类型
二.可选链
1.什么是可选链?
简单的说,就是可选类型的对象组成的链条
2.为什么会产生可选链?
2.1 假设有三个类, 人,狗,玩具
2.2 人里面有狗这个属性,狗里面有玩具这个属性, 玩具里面有价格这个属性
2.3 把玩具这个对象赋值给狗(让狗拥有玩具), 把狗这个对象赋值给人(让人拥有这只狗)
2.4 想要通过人来修改玩具的价格,就需要 person.dog.toy.price 来修改
2.5 person.dog这个值得类型是可选类型 ,因为人的狗属性可能为nil 属性,想要使用person.dog ,必须要强制解包
2.6 person.dog.toy也是可选类型,像这样由可选类型的对象组成的链条就是可选链
3.可选链注意点
3.1 利用可选链赋值的时候一定要解包
3.2 利用可选链取值的时候也不要忘记解包
3.3 利用可选链调用方法的时候 也要先解包
4.利用可选链赋值, 取值,调用方法
4.1 给可选链赋值:
1 person.dog!.toy!.price = 50 太危险 强制解包,如果没值,直接程序崩溃
2
3 if let dog = person.dog {
4 if let toy = dog.toy {
5 toy.price = 50
6 } 这样解包虽然安全,但是太麻烦
7 }
苹果在swift中推荐使用这种方式来给可选链赋值
1 person.dog?.toy?.price = 50
2 //当person.dog 为nil的时候,后面的操作就不再执行
4.2 从可选链取值: 从可选链中取出的值得类型一定是可选类型 (有可能取不到)
let price = person.dog?.toy?.price
4.3 可选链调用方法:系统会自动判断可选类型是否有值
person.dog?.toy?.flying()
三.协议
1.如何定义协议
1.1 swift中协议的方式和类,结构体,枚举相似
protocol SomeProtocol {
// 协议方法
}
1.2 例如:定义一个运动协议
1 protocol SportProtocol {
2 func playBasketball()
3 func playFootball()
4 }
2.声明一个类,并且遵守协议
2.1 声明一个基类(不继承其它类),并遵守协议
1 class SomeClass:FirstProtocol,AnotherProtocol {
2 // 类的内容
3 // 实现协议中的方法
4 }
5
6 例如:
7 class Person : SportProtocol {
8 var name : String = ""
9
10 func playBasketball() {
11 print("打篮球")
12 }
13
14 func playFootball() {
15 print("踢足球")
16 }
17 }
2.2 类继承自其他类,并遵守协议
1 class SomeClass:SomeSuperClass, FirstProtocol,AnotherProtocol {
2 // 类的内容
3 // 实现协议中的方法
4 }
3.OC swift不支持多继承, 但是可以通过协议,间接实现多继承
4.协议的继承关系
4.1 swift中的及协议和OC(NSObject)中的不同 是:NSObjectProtocol
1 protocol CrazySportProtocol : NSObjectProtocol {
2 func jumping()
3 }
4.2 一个协议,可以遵守另一个协议
1 protocol SportProtocol : CrazySportProtocol {
2 func playBasketball()
3 }
当一个类遵守了这个协议(SportProtocol) 相当于也遵守了CrazySportProtocol 协议, 所以必须实现这两个协议中的方法
5.协议的可选性
5.1 OC中协议可以定义为可选和必选,默认是必选的
5.2 默认情况下,swift中的协议都是必须实现的 ,否则编译器会报错
5.3 在swift中如何让协议成为可选的(不用必须实现)
要在协议前加 @objc ,可以保留OC某些特性,在方法前加optional 该方法就是可选的了
在实现协议方法时,在方法前面也要加@objc
1 @objc protocol SportProtocol {
2 func playBasketball()
3 func playFootball()
4 //加optional该方法就成为可选的了
5 optional func jumping()
6 }
7
8 class Person: SportProtocol {
9 @objc func playBasketball() { 在方法前也要加上关键字@objc,不管是可选还是必选
10 }
11 @objc func playFootball() {
12 }
13 @objc func jumping() {
14 }
15 }
6.协议在代理模式中的使用
6.1 一般来说协议都用weak来修饰(弱引用)
6.2 weak只能用来修饰类
6.3 在swift中协议既可以被类遵守,也可以被结构体,枚举遵守
6.4 如何让协议只能被类准守
在协议名称后面加上 :class 即可
四.闭包
1.什么是闭包?
闭包和OC中的block非常相似,一般都用来函数的回调
2.block的回顾
block作为属性的格式: `@property (nonatomic, strong) void(^finishedCallback)(NSString *)`;
block作为参数的定义格式:` (void (^)(NSString * str))finishedCallback`
3.闭包的格式:
(参数列表) -> (返回值类型)
4.闭包的使用
5.尾随闭包
1 // 尾随闭包 : 如果函数的最后一个参数是一个闭包.那么可以将函数调用写成尾随闭包
2 //就是把闭包写到()的后面, 本来是写在()里面的
3 tools?.loadData() { (result) in
4 print("在ViewController中获取到数据:\(result)")
5 }
6
7 // 如果函数有且只有一个参数,并且是一个闭包, 那么()也可以省略
8 tools?.loadData { (result) in
9 print("在ViewController中获取到数据:\(result)")
10 }
6.闭包的循环引用
6.1 一般在定义工具类的时候,会在工具类的方法中用到闭包
6.2 当工具类对闭包有强引用,一个控制器又调用包含该闭包的方法,在闭包方法中使用控制器的属性,就会发生循环引用
6.3 控制器调用方法,就会对工具类有一个强引用, 闭包又拿到控制器的属性,闭包对象就对控制器有一个强引用
6.4 在内存中就相当于这种表现
7.怎么解决闭包的循环引用
与oc中类型,只需要把闭包对控制器的引用改为弱引用
8.怎么改?
当闭包修改控制器的属性时,拿到控制器的属性时,把self(控制器)改成weakself即可
weak var weakself : ViewController? = self
五.swift项目的目录结构简介
1.swift项目目录中没有.h和.m的文件, 只有一个.swift的文件,相当于
2.swift目录中.swift文件就相当于oc中的.h和.m文件
3.在swift中,调用项目中的其他源文件不需要导入头文件 (一个 .swift文件就是一个源文件)
六.懒加载
1.懒加载的介绍
1.1 和OC中不同,swift有专门的关键字实现懒加载
1.2 懒加载本质:当第一次使用时再加载,而且只会被加载一次
2.swift中用lazy关键字来实现懒加载
2.1 懒加载格式
lazy var 变量: 类型 = { 创建变量代码 }()
= 后面是一个闭包 苹果推荐用闭包来实现懒加载,可在闭包中对变量属性进行初始化
2.2 懒加载的使用
1 lazy var names : [String] = {
2 return ["why", "yz", "lmj"]
3 }()
当执行到上面代码的时候,names不会被加载到内存中, 当names第一次使用时,才会被加载
无论names使用多少次,只会被加载一次,也就是说内存中只有一个names属性地址
七.swift中的常见注释
1.单行注释
和OC中的单行注释一样 使用 // 注释内容
2.多行注释
和OC中的多行注释格式一样 /* 注释内容 */
不同的是,swift中多行注释可以嵌套使用
3.文档注释
与oc中不一样 , swift中 用 /// 注释内容 来实现文档注释
4.分组注释
和oc不一样 oc: #pragma mark - 注释内容
swift: //MARK : - 注释内容
八.访问权限
1.internal :内部的
1.1 当不指定具体的访问权限时,默认为internal
1.2 internal的访问权限: 在当前项目(包)的任何地方都能访问
2.private : 私有的
private的访问权限: 在当前源文件中能够访问 一个 .swift文件就是一个源文件
3.public :公共的
3.1 public的访问权限 : 可以跨包访问
3.2 包的概念: 就是一个项目或一个框架 UIKit也是一个框架
九.异常处理
1.在swift中,如果一个方法的最后有一个throws,那么这个方法能抛出异常
正则表达式就能抛出异常:
NSRegularExpression(pattern: <#T##String#>, options: <#T##NSRegularExpressionOptions#>)
2.如果一个方法抛出异常,必须要对异常进行处理,否则编译报错
3.异常处理的三种方式
3.1 try : 手动处理异常,可以拿到异常(error)
要在方法前面加上try 而且外面要用do 包装
//try方式 --> 手动处理异常, 并且可以获取到最终的异常结果
do { //如果有异常error有值
let regex = try NSRegularExpression(pattern: "", options: .CaseInsensitive)
} catch { //通过error拿到异常结果
print(error)
}
3.2 try? : 系统处理异常
try?方式 : 如果有异常,则返回nil,如果没有异常,则返回结果 结果(regex)为可选类型
let regex = try? NSRegularExpression(pattern: "", options: .CaseInsensitive)
regex?.matchesInString("", options: [], range: NSMakeRange(0, 0))
3.3 try! :告诉系统不可能有异常
try!方式(不推荐) 注意:一旦发生异常,程序就会崩溃
let regex = try! NSRegularExpression(pattern: "", options: .CaseInsensitive)
十.如何抛出异常
1.在方法参数的后面加上 throws ,一定要有返回值
2.在某些具体的情况下抛出异常
比如:传的参数不对等等 ,内部要对参数进行判断
3.抛出的异常,一般定义为枚举类型 枚举后面要跟上 ErrorType 这种类型
十一.OC和swift相互调用
1.swift中调用oc
1.1 创建一个桥接文件 (.h的文件) 文件名一般为 Bridge.h
1.2 在桥接文件中导入oc的头文件
1.3 配置桥接文件 工程 —> BuildSetting —> 搜索bridging 在后面写入Bridge.h 的相对路径
2.oc中调用swift
2.1 项目名称要规范 (不能有中文和特殊字符)
2.2 swift中的类,属性,方法名 前面要加 public
2.3 在oc文件中导入 工程名-Swift.h 的头文件 工程名-Swift.h 系统会自动生成