//: Playground - noun: a place where people can play
import UIKit
var str = "Swift之闭包结构"
print(str)
/*
函数的格式:
func 函数名(参数) ->返回值类型 {
代码块
return 返回值
}
闭包的格式:
let 闭包名 = {
(参数列表) ->返回值 in
闭包体
}
闭包的最外层用大括号包围,内部由闭包关键字in来进行分割,关键字in前面为闭包结构的参数列表和返回值,其书写规则和函数一致,in关键字后面为闭包体,用于实现具体功能。另外闭包的返回值是可以省略的
let 闭包名 = {
(参数列表) in
闭包体
}
这时如果有return 返回,闭包会自动将return返回的数据类型作为返回值类型
*/
//实现排序效果,//Any在Swift中代表任意类型。inout允许修改参数,传参数前加&
func mysort(array:inoutArray,sortClus:(Int,Int)->Bool) -> Array{
// 冒泡排序
for indexI in array.indices {
if indexI == array.count -1{
break
}
for indexJ in 0...((array.count-1) - indexI -1) {
if sortClus(indexJ,indexJ+1) {
}
else{
//元素交换
// swap(&array[indexJ], &array[indexJ+1])
array.swapAt(indexJ, indexJ+1)
}
}
}
return array
}
var array:Array = [1,2,9,3,6,5,4]
mysort(array: &array,sortClus: { (index:Int, nextIndex:Int) ->Bool in
return (array[index]as! Int) > (array[nextIndex]as! Int)
})
print(array)
//as!的作用是类型转换
//编写一个类进行排序测试
//定义一个学生类
class Student{
let name : String
let score :Int
init(name:String,score:Int) {
self.name = name
self.score = score
}
}
//创建四个学生
let stu1 = Student(name:"zhangsan", score: 89)
let stu2 = Student(name:"lisi", score: 93)
let stu3 = Student(name:"wangwu", score: 75)
let stu4 = Student(name:"sunliu", score: 95)
var stuArr:Array = [stu1,stu2,stu3,stu4]
//调用上面的函数
mysort(array: &stuArr) { (index, nextIndex) ->Bool in
return (stuArr[index]as! Student).score>(stuArr[nextIndex]as! Student).score
}
print((stuArr[0]as! Student))
//闭包的优化写法
//1、省略返回值
mysort(array: &stuArr) { (index, nextIndex)in
return (stuArr[index]as!Student).score > (stuArr[nextIndex]as!Student).score
}
//2、省略return
mysort(array: &stuArr) { (index, nextIndex) in
(stuArr[index]as!Student).score > (stuArr[nextIndex]as!Student).score
}
//3、将参数列表和闭包关键字in省略,优化后:
mysort(array: &stuArr) {
(stuArr[$0]as!Student).score > (stuArr[$1]as!Student).score
}
//后置闭包
/*
闭包常常会作为函数的参数来使用,函数在调用时,参数是写在小括号中的参数列表中的,而闭包又是一个写在大括号中的代码块,如此嵌套并不直观。所以,Swift中提供了后置闭包的写法。当函数的最后一个参数为闭包参数时,在调用函数时,开发者可以将闭包结构脱离出函数参数列表,追加在函数的尾部,增强代码的可读性。
后置闭包语法简化了代码的结构,还有个小技巧,如果函数只有一个参数,且这个参数是一个闭包类型的参数,则开发者在调用函数时,使用后置闭包的写法可以直接将函数的参数列表省略
*/
//只有一个闭包参数的函数
func myfunc(clsous:(Int,Int)->Bool){
}
//进行闭包的后置 可以省略参数列表
myfunc{
$0 > $1
}
/*
逃逸闭包
当闭包传递函数时,系统会为此闭包进行内存的分配。在Swift语言中,含有逃逸闭包与非逃逸闭包的概念。所谓逃逸闭包是指函数内的闭包在函数执行结束后在函数外依然可以进行使用,非逃逸闭包是指当函数的生命周期结束后闭包也将被销毁。换句话说,非逃逸闭包只能在函数内部使用。默认情况下函数参数中的闭包都是非逃逸闭包,这样的优点是可以提高代码性能,节省内存消耗。在Swift2.0时声明非逃逸闭包,需要使用@noescape修饰
比如: func myfunc11(closous:@noescape (Int,Int)->Bool){
}
使用@noescape在新版的Xcode中Swift3.0下会报错:@noescape is the default and has been removed
注意,非逃逸闭包也不可以作为返回值返回,也不可赋值给外部变量。
逃逸类型的闭包常用于异步操作中,例如一个后台请求完成后要执行闭包回调,需要使用逃逸闭包;也常见于存储, 需要存储闭包作为属性,全局变量或其他类型做稍后使用。
*/
class ClassA {
// 接受非逃逸闭包作为参数
func someMethod(closure: () -> Void) {
// 想干什么?
print("noescape,非逃逸闭包")
}
}
class ClassB {
let classA = ClassA()
var someProperty = "Hello"
func testClosure() {
classA.someMethod {
// self 被捕获
someProperty = "闭包内..."
}
}
}
var classb = ClassB()
classb.testClosure()
func someMethod(closure: @escaping (Int) -> Void) {
// 特别行动
print("escaping,逃逸闭包")
print(index)
// return arr
}
/*
自动闭包
Swift语言中还有一种语法,可以实现对简单闭包的自动生成,这种闭包通常称为自动闭包,自动闭包参数的使用是非常严格的,首先此闭包不能够有参数,其次在调用闭包函数传参时,此闭包的实现只能由一句表达式组成,闭包的返回值即为此表达式的值,自动闭包参数由@autoclosure来声明,
*/
func myfuncauto(closure: @autoclosure ()->Bool){
print(closure)
}
//调用函数时,直接传入一个表达式即可,编译器会自动生成闭包参数
myfuncauto(closure:1+2+3>10)
//练习
//0、将数字字符串的整数部分 用,隔开,比如每三位一个逗号,1234567就成了1,234,567
func revertStr(preStr:String,num:Int) ->String{
var numStr = preStr
var subStrs = numStr.split(separator:".")
var intStr = subStrs[0]
var dotStr = subStrs[1]
func getString(str: String,num:Int)-> String{
if str.characters.count < num{
return str
}
var string = str
let inum = str.characters.count%num//取余
let ge = str.characters.count / num//取整
let numIndex = (inum == 0) ? ge : (ge+1) //取组数
// 截串
var reversStr = String(string.reversed())
string = ""
var index = 1
while index < numIndex {
var substrsq = reversStr.split(separator: reversStr[reversStr.index(reversStr.startIndex, offsetBy: num)])
reversStr.removeSubrange(reversStr.startIndex...reversStr.index(reversStr.startIndex, offsetBy: num-1))
string += substrsq[0] + ","
index += 1
}
print(reversStr,string)
if reversStr.characters.count >0{
string += reversStr
}
else{
string.remove(at: string.endIndex)
}
return String(string.reversed())
}
return getString(str:String(intStr), num:3)+"." + dotStr
}
print(revertStr(preStr:"23412345.23", num: 3))
//1、编写计算阶乘的函数
func caculateJ(pram:Int)->Int{
guard pram>0else {
return 0
}
var result = 1
var tem = pram
while tem>1 {
result *= tem
tem -= 1
}
return result
}
print(caculateJ(pram:5))
//2、编写函数,功能是:判断输入的字符是否是数字字符
func funcIfNum(param:String)->Bool{
if param>="0"&¶m<="9" {
return true
}
else{
return false
}
}
funcIfNum(param: "9")
//3、编写函数,功能是:将两个两位数的正整数a,b合并成一个整数c,合并规则是将a的十位和个位分别放在c的千位和个位,将b的十位和个位分别放在c的百位和十位
func combine(firstP:Int,SecondP:Int)->Int{
return (firstP/10%10)*1000 + (SecondP/10%10)*100 + SecondP%10 * 10 + firstP%10
}
print(combine(firstP:23, SecondP: 15))
//4、将字符串中的小写字母变大写,大写变小写
func transformString(param:String)->String{
var newStr = ""
for char in param.characters {
if char>="a"&&char<="z" {
newStr.append(String(char).uppercased())
}
else if char>="A"&&char<="Z"{
newStr.append(String(char).lowercased())
}else{
newStr.append(char)
}
}
return newStr
}
print(transformString(param:"Hello World!"))
//5、编写函数,输入大于0的数字,将不大于这个数字的所有正奇数的和与正偶数的和以元组的形式返回
func outNumWithPreNum(prenum:Int)->(Int,Int){
if prenum<=0 {
return (0,0)
}
var sumJ = 0
var sumO = 0
var temp = prenum
while temp>0 {
if temp%2 ==0 {
sumO += temp
}
if temp%2 ==1 {
sumJ += temp
}
temp -= 1
}
return (sumJ,sumO)
}
print(outNumWithPreNum(prenum:10))
//6、输入一组不确定个数的整数,统计其中正数和负数的个数,0不计入统计
func countNum(param:Int...)->(Int,Int){
var fNum = 0
var Znum = 0
for p in param {
if p>0 {
Znum += 1
}
else if p<0{
fNum += 1
}
}
return (Znum,fNum)
}
print(countNum(param:1,2,-2,-1,-3,-5,0,8,9))
//7、编写函数,输入圆的半径,输出圆的周长和面积
func cacluteCircle(r:Float)->(Float,Float){
return (Float.pi*r*2,Float.pi*r*r)
}
cacluteCircle(r: 3)
//8、编写函数,输入一组整数,将其中最大的数和最小的数返回
func funcMaxAndMin(param:Int...)->(Int,Int){
return (param.max()!,param.min()!)
}
funcMaxAndMin(param: 1,2,3,4,-6)