我在swift的一個(gè)函數(shù)里面,參數(shù)里需要傳遞一個(gè)指針類型的Int,但是這個(gè)函數(shù)里面還有一個(gè)逃逸閉包@escaping,于是就會(huì)報(bào)錯(cuò)這樣:Escaping closure captures ‘inout’ parameter ‘selectRow’ ,意思是說:逃逸閉包補(bǔ)貨了一個(gè)inout參數(shù) selectRow
需求
我每次調(diào)用下面的swift方法,都會(huì)彈出一個(gè)PickerView,并且,設(shè)置label的text,同時(shí),記錄上次選中的selectRow
func setTimePicker2(selectRow:inout Int,label:UILabel){
let vc = TDWPickerVC(items: timeItems, titleLabelStr: "請選擇時(shí)間段",selectRow: selectRow) {
print("點(diǎn)擊取消")
} confirmBlock: { (str,row) in
print("點(diǎn)擊確定",str)
selectRow = row
label.text = str
}
print("time1VSelectRow=",selectRow )
vc.modalPresentationStyle = .custom
vc.modalTransitionStyle = .crossDissolve
navigationController?.present(vc, animated: true, completion: nil)
}
下面是調(diào)用的代碼
var time3VSelectRow = 0//類成員變量
setTimePicker2(selectRow: &time3VSelectRow, label: time3Label)//方法中的調(diào)用
``
再看控制器的定義里面有一個(gè)@escaping的逃逸閉包類型
```swift
init(items:[String],titleLabelStr:String,selectRow:Int, cancleBlock:@escaping BlockVoid,confirmBlock:@escaping BlockStr) {
self.titleLabelStr = titleLabelStr
self.cancleBlock = cancleBlock
self.confirmBlock = confirmBlock
self.items = items
self.selectRow = selectRow
super.init(nibName: "TDWPickerVC", bundle: nil)
}
錯(cuò)誤原因就是編譯器不允許逃逸閉包@escaping捕獲inout類型參數(shù),因?yàn)閕nout類型傳入的是一個(gè)指針,參數(shù)可以在外面更改,不安全
如果上面代碼沒有逃逸閉包,那么傳入一個(gè)inout Int 類型就沒問題了。setTimePicker2方法在執(zhí)行的時(shí)候同時(shí)更改selectRow這個(gè)Int數(shù)據(jù)
解決方法
創(chuàng)建一個(gè)類,用類包裹基礎(chǔ)數(shù)據(jù)類型Int這個(gè)類只用來存選中行數(shù),這個(gè)類只用來存選中行數(shù),因?yàn)橹苯佑没A(chǔ)數(shù)據(jù)類型inout int,不能在里面再調(diào)用逃逸閉包@escaping,但是參數(shù)傳入類的對象,是直接操作對象里面的成員,操作的地址相同。
class TimeVSelected:NSObject{
var selectRow : Int = 0
}
函數(shù)定義成這樣,參數(shù)列表里面要類對象TimeVSelected,原來Int類型的地方用 selectobj.selectRow 對象的成員變量來代替
func setTimePicker(selectobj: TimeVSelected,label:UILabel){
//注意這里用selectobj.selectRow代替之前的selectRow
let vc = TDWPickerVC(items: timeItems, titleLabelStr: "請選擇時(shí)間段",selectRow: selectobj.selectRow) {
print("點(diǎn)擊取消")
} confirmBlock: { (str,row) in
print("點(diǎn)擊確定",str)
selectobj.selectRow = row
print("selectobj地址是:",selectobj)
label.text = str
}
vc.modalPresentationStyle = .custom
vc.modalTransitionStyle = .crossDissolve
navigationController?.present(vc, animated: true, completion: nil)
}
容易產(chǎn)生的問題
之前我也試過,既然類對象可以直接修改里面的對象,inout 和 @escaping不能一起用,那我為什么不能直接去掉inout這樣設(shè)置參數(shù)列表:
func setTimePicker2(selectRow:Int,label:UILabel)
這樣會(huì)報(bào)錯(cuò),因?yàn)楹瘮?shù)參數(shù)是不能在函數(shù)體里面改變的,函數(shù)參數(shù)被認(rèn)為是let常量,如下:報(bào)錯(cuò)
func setTimePicker2(selectRow:Int,label:UILabel){
let vc = TDWPickerVC(items: timeItems, titleLabelStr: "請選擇時(shí)間段",selectRow: selectRow) {
print("點(diǎn)擊取消")
} confirmBlock: { (str,row) in
print("點(diǎn)擊確定",str)
selectRow = row //這里會(huì)報(bào)錯(cuò)Cannot assign to value: 'selectRow' is a 'let' constant
label.text = str
}
print("time1VSelectRow=",selectRow )
vc.modalPresentationStyle = .custom
vc.modalTransitionStyle = .crossDissolve
navigationController?.present(vc, animated: true, completion: nil)
}
xcode截圖如下:

我們用類對象在函數(shù)體也不能改變,但是對象成員可以改變,看我下面的截圖,報(bào)錯(cuò)也是說對象是let類型不能改:
func setTimePicker(selectobj: TimeVSelected,label:UILabel){
let vc = TDWPickerVC(items: timeItems, titleLabelStr: "請選擇時(shí)間段",selectRow: selectobj.selectRow) {
print("點(diǎn)擊取消")
} confirmBlock: { (str,row) in
print("點(diǎn)擊確定",str)
selectobj.selectRow = row
selectobj = TimeVSelected()//這里就會(huì)報(bào)錯(cuò),因?yàn)閟electobj是函數(shù)參數(shù),不能賦值
print("selectobj地址是:",selectobj)
label.text = str
}
vc.modalPresentationStyle = .custom
vc.modalTransitionStyle = .crossDissolve
navigationController?.present(vc, animated: true, completion: nil)
}

以前用C++的時(shí)候這種函數(shù)參數(shù)列表里的參數(shù)叫形參,是可以改的,但是改完以后,不會(huì)影響函數(shù)傳入之前的值,形參是臨時(shí)變量,函數(shù)結(jié)束就釋放了,swift就不一樣,類對象作為函數(shù)參數(shù),實(shí)際就是把類對象地址傳過來,跟c++一樣,改變對象里成員值,對象也被改變
print("timeVselected1地址是:",timeVselected1)
通過打印證明函數(shù)參數(shù)的類對象傳遞和C++的地址傳遞一樣,函數(shù)外和內(nèi)部都是一個(gè)地址

總結(jié)
以后再需要傳遞那種在函數(shù)里改變函數(shù)外的值,恰好函數(shù)內(nèi)部有逃逸閉包@escaping的,就用類對象傳遞到函數(shù)中,再改變類對象的成員,這樣就能在函數(shù)內(nèi)改變函數(shù)外的值了。