最近在做的小項目出現(xiàn)了一個問題。當(dāng)presentViewController時內(nèi)存上升(在debug navigator下觀察),dissmissViewController時竟然沒有下降。我第一反應(yīng)就是哪里出現(xiàn)循環(huán)引用了。于是我手工遍歷一遍代碼,還好代碼量不是太多,很快就找到問題的根源。
下文的block其實就是swift中的closure閉包,兩者非常想想。
問題描述:
有時候為了減少重復(fù)代碼,我們會將重復(fù)的代碼抽取出去放在一個函數(shù)里面,然后根據(jù)不同參數(shù)來調(diào)用該函數(shù)。
func editAccountBook(item:AccountBookBtn?, indexPath:NSIndexPath, sureBlock:(String, String)->Void){
customAlertView.title = item?.btnTitle ?? ""
customAlertView.initChooseImage = item?.backgrountImageName ?? "book_cover_0"
customAlertView.cancelBlock = {[weak self] in
if let strongSelf = self{
strongSelf.customAlertView.removeFromSuperview()
}
}
customAlertView.sureBlock = sureBlock
UIApplication.sharedApplication().keyWindow?.addSubview(self.customAlertView)
}
比如上面這個函數(shù),目光集中在倒數(shù)第二行的sureBlock,這個sureBlock是外部傳進來的。我們知道Block的原理就是一個結(jié)構(gòu)體,像函數(shù)傳參這種一般都是傳sureBlock的結(jié)構(gòu)體指針。在使用屬性的時候,swift允許我們不加self,所以customAlerView是被self引用到的。而只要這個sureBlock里面有對self的強引用,將sureBlock賦值給customAlerView.sureBlock的話就會造成循環(huán)易用。所以說,抽代碼要小心吶。
再看看editAccountBook這個函數(shù)被調(diào)用的地方,一開始我是這么寫的
let block:(String,String)->Void = {(title, imageName) in
//建一個數(shù)據(jù)庫
let currentTime = Int(NSDate().timeIntervalSince1970)
let dbName = customAccountName + "\(currentTime)" + ".db"
let item = AccountBookBtn(title: title, count: "0筆", image: imageName, flag: false, dbName: dbName)
//插入賬本
self.mainVCModel.addBookItemByAppend(item)
self.mainView.accountBookBtnView.insertItemsAtIndexPaths([indexPath])
//退出alertview
self.customAlertView.removeFromSuperview()
}
editAccountBook(nil, indexPath: indexPath, sureBlock: block)
當(dāng)時覺得這個block是臨時生成的,里面雖然引用到self,應(yīng)該也沒什么關(guān)系。殊不知這個block在傳給editAccountBook這個函數(shù)的時候就間接地被self引用到了,所以就造成了循環(huán)引用。所以用block真是要特別小心。特別是一些自己寫的函數(shù)。
解決辦法
解決辦法很簡單,在block的開頭加一些list就好。如下
editAccountBook(nil, indexPath: indexPath){[weak self](title, imageName) in
if let strongSelf = self{
//建一個數(shù)據(jù)庫
let currentTime = Int(NSDate().timeIntervalSince1970)
let dbName = customAccountName + "\(currentTime)" + ".db"
let item = AccountBookBtn(title: title, count: "0筆", image: imageName, flag: false, dbName: dbName)
//插入賬本
strongSelf.mainVCModel.addBookItemByAppend(item)
strongSelf.mainView.accountBookBtnView.insertItemsAtIndexPaths([indexPath])
//退出alertview
strongSelf.customAlertView.removeFromSuperview()
}
}
這里用了swift的省略寫法,當(dāng)函數(shù)最后一個參數(shù)是block時,可以將整個block移到函數(shù)的末尾??梢钥吹竭@里使用了[weak self],這一句會將selfwrap成一個optional,所以在使用的時候得unwrap。其中的if let strongSelf = self就是unwrap??吹竭@里,用Objc開發(fā)的同學(xué)應(yīng)該很熟悉了,在ARC下block的寫法和swift里的思想都是一模一樣的,格式有點不同罷了。
自己寫的總結(jié),方便以后查看。