Swift3.0 - 真的很简单
Swift3.0 - 数据类型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可选值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 对象和类
Swift3.0 - 属性
Swift3.0 - 函数和闭包
Swift3.0 - 初始化和释放
Swift3.0 - 协议protocol
Swift3.0 - 类和结构体的区别
Swift3.0 - 枚举
Swift3.0 - 扩展
Swift3.0 - 下标
Swift3.0 - 泛型
Swift3.0 - 异常错误
Swift3.0 - 断言
Swift3.0 - 自动引用计数(strong,weak,unowned)
Swift3.0 - 检测API
Swift3.0 - 对象的标识
Swift3.0 - 注释
Swift3.0 - 元类型
Swift3.0 - 空间命名
Swift3.0 - 对象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 类簇
Swift3.0 - 动态调用对象(实例)方法
Swift3.0 - 文本输出
Swift3.0 - 黑魔法swizzle
Swift3.0 - 镜像
Swift3.0 - 遇到的坑
函数的几种类型
- 无参无返
func greet() -> Void {
}
// 或者
func greet(){
}
- 有参无返
func greet(person: String, day: String) {
return "Hello \\\\(person), today is \\\\(day)."
}
greet(person: "Bob", day: "Tuesday")
思考1: 如何省略外部参数名?
greet("John", "Wednesday")
// 实现代码
func greet(_ person: String, _ day: String) -> String {
return "Hello \\\\(person), today is \\\\(day)."
}
- 有参有返
func greet(_ person: String, on day: String) {
return "Hello \\\\(person), today is \\\\(day)."
}
- 无参有返
func greet(_ person: String, on day: String) -> String {
return "Hello \\\\(person), today is \\\\(day)."
}
中级思考
- 参数和返回值
1.参数可以是那些?
基本类型的值,对象,数组,字典,元组,可变数量的参数,函数,闭包函数,协议,结构体,枚举值
2.怎么定义参数
a. 单值
func calculate(a:Int){
let b = a
}
b.多值
func calculate(a:Int...){
for _ in a{
}
}
// 调用
calculate(a: 1,2,3,4,5,6)
c.元组
func calculate(a:(name:String,age:Int)){
let name = a.name;
let age = a.age;
}
d.数组
func calculate(a:[String]){
for student in a {
}
}
e.定义字典
func calculate(a:[String:Int]){
for student in a {
print(student.key)
print(student.value)
}
}
f.函数作为参数
func add(a:Int,b:Int)->Int{// 作为函数参数的函数
return a+b
}
func calculate(a:(Int,Int)->Int){// 定义的参数为函数的函数
a(2,1)// 执行函数
}
calculate(a: add);// 执行函数
g.上面函数的闭包写法
calculate { (a,b) -> Int in
return a+b
}
calculate { (a,b) in a+b } // 省略写法(由于swift有推断能力,这样写它就能帮你推断出来上面的写法)
h. 参数为协议的方法
protocol Player{ // 定义协议
func play()
}
func playMusicWithPlayer(player:Player){
player.play()
}
i.参数为结构体
struct Student{
var name:String
var age:Int
};
func getStudentDescription(student:Student){
print(student.name)
print(student.age)
}
j.参数为枚举类型
// 定义枚举值
enum CarType:String{
case Lincoln = "林肯"
case MERCURY = "水星"
case SUZUKI = "铃木"
}
// 参数为协议的方法
func describeCar(carType:CarType){
print(carType.rawValue);
}
- 函数的内部定义函数
需求: 创建一个接口,输入true 返回 两个数相加的函数,输入false 返回两个数相减的函数
func generateFuncByFlag(flag:Bool)->(Int,Int)->Int{
// 定义两数字相加函数
func add(a:Int,b:Int)->Int{
return a+b;
}
// 定义两数字相减函数
func decrease(a:Int,b:Int)->Int{
return a-b;
}
// 根据输入的条件返回对应的函数
if flag{
return add
}else{
return decrease
}
}
// 生成对应的函数
let addFunc = generateFuncByFlag(flag: false)
// 执行返回的函数
print(addFunc(1,2))
- 设置默认参数值
func addStudent(student:(name:String,score:Double)=("姓名",12)){
print(student.name)
print(student.1)
}
addStudent()
addStudent(student: ("酷走天涯",99))
提示:
元组类型,不能分别给参数赋值,比如像下面这样
// 这样是错误的方式
func addStudent(student:(name:String = "酷走天涯",score:Double = 12 )){
print(student.name)
print(student.1)
}
- inout的使用
需求: 创建一个函数,交换两个Int类型值
a.如果参数为let修饰的常量
func swapTwoInts( a: Int, b: Int){
let temporaryA = a
a = b
b = temporaryA
}
提示:
报错:系统提示错误,说常量不能修改值
b.我们将参数变成变量var
func swapTwoInts( var a: Int, var b: Int){
let temporaryA = a
a = b
b = temporaryA
}
提示:
报错,不能使用var 修饰参数
c.inout 修饰的参数可以修改值
func swapTwoInts( a: inout Int, b:inout Int){
let temporaryA = a
a = b
b = temporaryA
}
var a = 30
var b = 40
swapTwoInts(a: &a, b: &b)
print(a)
print(b)
运行结果:
40
30
你需要注意的
1.inout的位置 在: 后面,数据类型前面
2.inout 修饰的参数不能有默认值
3.inout 不能用于修饰多值(如a:Int...)
- 定义函数类型的变量
func swapTwoInts( a: inout Int , b:inout Int){
let temporaryA = a
a = b
b = temporaryA
}
var swap1:( inout Int, inout Int)->Void = swapTwoInts
注意:函数类型的变量不能用标签修饰参数
// 错误的写法 不能使用a,b标签
var swap1:( a :inout Int, b: inout Int)->Void = swapTwoInts
// 你应该像下面这样
var swap1:( _ :inout Int, _: inout Int)->Void = swapTwoInts
// 或者下面这样也可以,a,b 不一定要和实际函数对应
var swap1:( _ a:inout Int, _ b: inout Int)->Void = swapTwoInts
// 建议还是用下面这种
var swap1:( inout Int, inout Int)->Void = swapTwoInts
- 定义闭包类型数据
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let customerProvider = { customersInLine.remove(at: 0)}
print(customersInLine.count)
print("Now serving \\\\(customerProvider())!")
print(customersInLine.count)
运行结果:
5
Now serving Chris!
4
提示:上面那种闭包其实是五参有返的闭包形式,原形如下
let customerProvider:()->String= { customersInLine.remove(at: 0)}
- 关键字 @discardableResult
先看一段代码:
class OSStudent{
var name:String!
var score:Double!
func setNewScore(score:Double)->Bool{
if name == nil || name.isEmpty{
return false
}
self.score = score
return true
}
}
OSStudent().setNewScore(score: 34.0)
注意:
函数的setNewScore 方法有返回值,但是调用的时候,没有使用常量或者变量接受这个返回值,系统会产生警告如下图
我们通过加关键字@discardableResult去除那种警告
@discardableResult
func setNewScore(score:Double)->Bool{
if name == nil || name.isEmpty{
return false
}
self.score = score
return true
}
注意
如果你没有添加这个关键字,系统默认添加的是 @warn_unused_result ,有返回值没有使用会发生警告
高级思考
- 如何获取,函数自己的名称,在那个文件中,在文件多少行
// 定义一个获取获取函数名称,获取文件路径的函数
func getFunctionName(name:String = #function,line:Int = #line,file:String = #file){
print(name)
print(line)
print(file)
}
// 比如我们要获取下面函数的信息,只需要将函数写入要获取信息函数的内部调用即可
func getUserName(){
getFunctionName()
}
// 执行函数
getUserName()
运行结果:
getUserName()
152
/var/folders/gk/zc__29js08g1g03xrzgl8m1m0000gn/T/./lldb/2184/playground65.swift
- 编译器可能没有那么智能
// 定义一个父类
class Person{
}
// 定义一个男人
class Man:Person{
}
// 定义一个女人
class Woman:Person{
}
// 定义三个描述人的方法
func describePerson(_ person:Person){
print("我是人类")
}
func describePerson(_ woman:Woman){
print("我是女人")
}
func describePerson(_ person:Man){
print("我是男人")
}
// 定义一个描述男人的女人的方法
func descripePerson(_ person:Person,_ woman:Woman){
describePerson(person)
describePerson(woman)
}
// 执行
descripePerson(Man(), Woman())
结果:
我是人类
我是女人
分析:
参数man 在值没有传入之前,被默认为Person 进行编译了,所以不管我们传入男人或者女人都之调用人类描述的方法。
那么我们应该怎么处理这个问题呢?
func descripePerson(_ person:Person,_ woman:Woman){
if person is Woman{
describePerson(person as! Woman)
}else{
describePerson(person as! Man)
}
describePerson(woman)
}
运行结果:
我是男人
我是女人
下面这种写法也是可以的
func descripePerson(_ person:Person,_ woman:Woman){
if let woman = person as? Woman{
describePerson(woman)
}else{
describePerson(person as! Man)
}
describePerson(woman)
}
- 泛型
需求: 设计一个接口,交换两个元素(数字,字符,对象)的值
func swap<T>(a:inout T,b:inout T){
(a,b) = (b,a)
}
测试1
var a = "你好"
var b = "酷走天涯"
print("交换前---------------------")
print(a)
print(b)
swap(&a, &b)
print("交换后----------------------")
print(a)
print(b)
运行结果:
交换前---------------------
你好
酷走天涯
交换后----------------------
酷走天涯
你好
测试2
class Woman{
var name = "女人"
init(name:String) {
self.name = name
}
}
print("交换前---------------------")
print(a.name)
print(b.name)
swap(&a, &b)
print("交换后----------------------")
print(a.name)
print(b.name)
运行:
交换前---------------------
小红
小白
交换后----------------------
小白
小红
提示
交换的必须是相同的对象
*@escaping 用法
var downloadComplate:(Bool)->()
func downloadResource(url:String,complate:(Bool)->()){
downloadComplate = complate
// 异步下载,下载完成调动
downloadComplate(true)
// 下载失败
downloadComplate(false)
}
运行
编译报错,提示没有加@escaping
@escaping 作用
我们经常在下载等异步操作完成时,才调用闭包函数,我们有可能暂时不要把这个闭包存放在数组中,或者使用属性去引用它,那么这个时候就需要使用这个关键了
修改代码
var downloadComplate:((Bool)->())
func downloadResource(url:String,complate:@escaping (Bool)->()) {
downloadComplate = complate
// 异步下载,下载完成调动
downloadComplate(true)
// 下载失败
downloadComplate(false)
}
报错提示:
downloadComplate 使用之前必须初始化
所以进行初始化
var downloadComplate:((Bool)->())! // 加? 也可以,但是在调用时,要进行解包
func downloadResource(url:String,complate:@escaping (Bool)->()) {
downloadComplate = complate
// 异步下载,下载完成调动
downloadComplate(true)
// 下载失败
downloadComplate(false)
}
我们如何调用
downloadResource(url: "www.baidu.com") { (flag) in
print(flag)
}
如果我们不需要引用完全可以不使用关键字@escaping
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
- 关键字@autoclosure 的用法
a.不加自动闭包的关键字@autoclosure
func serve(customer customerProvider: () -> String) {
print(customerProvider())
}
serve { () -> String in
return "没加@autoclosure"
}
运行结果:
没加@autoclosure
b.添加@autoclouse
func serve(customer customerProvider: @autoclosure () -> String) {
print (customerProvider())
}
serve(customer: "加了@autoclosure") // 调用
是不是感觉参数像是字符串,而是下面这样,系统帮你自动闭包了
serve(customer: { "加了@autoclosure"})
如果还不清楚,其实是参数是一个返回值
serve(customer: { return "加了@autoclosure"})
完整的写法其实是下面这样
serve(customer: { () in return "加了@autoclosure"})
c. @autoclosure 和 @escaping 组合使用方法
func serve(customer customerProvider: @autoclosure @escaping() -> String) {
customerProvider1 = customerProvider
print (customerProvider())
}
serve(customer: customersInLine.remove(at: 0))
提示:
其实自动闭包给人可能造成一种表意不清的感觉,建议使用的时候,一定要注释说明,或者不要使用。
d. @noescape
func calculate(fun :@noescape ()->()){
}
提示:
1.系统默认为@onescape 的类型
2.不能被引用
3.不能在异步执行