//: 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<Any>,sortClus:(Int,Int)->Bool) -> Array<Any>{
// 冒泡排序
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<Any> = [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<Any> = [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)