2017-06-23 81 views
0

我不理解閉包捕獲數據的這個概念。有人可以使用閉包來編寫示例代碼,這些閉包顯示數據永遠不會被破壞。我已經閱讀了Apple文檔,但我仍然感到困惑。並且還怎麼「無主」和「弱」使封閉任何區別...閉包如何捕獲數據?

class TableViewController: UITableViewController { 

var allWords = [String]() 
var usedWords = [String]() 


override func viewDidLoad() { 
    super.viewDidLoad() 

    if let allWordsPath = Bundle.main.path(forResource: "start", ofType: "txt"){ 

     if let startWords = try? String(contentsOfFile: allWordsPath){ 

      allWords = startWords.components(separatedBy: "\n") 

     }else{ 

      allWords = ["Cake"] 
     } 

     startGame() 
    } 

    navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Make Word", style: .plain, target: self, action: #selector (makeWord)) 
} 

func startGame(){ 

    allWords = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: allWords) as! [String] 
    title = allWords[0] 
    usedWords.removeAll(keepingCapacity: true) 

} 

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return usedWords.count 
} 

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Word", for: indexPath) 
    cell.textLabel?.text = usedWords[indexPath.row] 
    return cell 

} 


func makeWord() { 

    let ac = UIAlertController(title: "Add Word", message: nil, preferredStyle: .alert) 
    ac.addTextField(configurationHandler: nil) 


    let submit = UIAlertAction(title: "Submit", style: .default){ [unowned self,ac] 

     (action: UIAlertAction!) in 
     let answer = ac.textFields?[0] 
     self.submit(answer: (answer?.text)!) 

     } 

    ac.addAction(submit) 
    present(ac,animated: true) 
} 


var number = 10 
func submit(answer: String){ 
    usedWords.append(answer) 
    tableView.reloadData() 

} 

這裏怎麼做無主的工作,如果我們沒有明確重新分配的東西..

+0

http://alisoftware.github.io/swift/closures/2016/07/25/closure-capture-1/ – Pochi

+0

我不明白他的榜樣。 –

+0

檢查我的答案。 Btw關閉不保證你的數據不會被破壞。它們只是允許您指定應該如何處理數據,以及在被銷燬的情況下如何處理。它完全有效的將變量設置爲「弱」,然後在封閉內部簡單地檢查它。 – Pochi

回答

0

你應該先搜索強,弱和無主之間的區別。這裏有很多關於它的答案。

不管怎麼說,在這種特殊情況下:

你關閉了這個代碼:

[unowned self,ac] 

這就是所謂的 「捕獲列表」。它表示當創建塊時應該由值「捕獲」的事物。 (如果在這裏沒有指定它們,並且在塊之後的某處更改了值,則塊內的值也將被更改)。

之所以自我是無主的,不需要被釋放是因爲無主的手段:

「別擔心內存管理這個變量,它會永遠 具有的價值我的關閉持續時間「

因此,回到無主的自我,你應該從閉包聲明弱或無主自變量的原因是因爲如果不是,你會創建一個保留週期。只要有東西引用它們,事物就不能被釋放。所以在這種情況下,你的TableViewController保持你的閉包存活,並且你的閉包保持你的TableViewController存活。因此,因爲它們互相引用,它們都不能正確釋放。 - >內存泄漏

所以我們可以得出結論,自我必須弱或無主。對於這個例子中的所有意圖和目的,它們都完全一樣。它們都通過消除閉合保持自我活力的能力來達到「打破保留週期」的目的。那麼你會問自己誰會釋放自己?你的關閉不關心。但在你的關閉之外思考。你的閉包被你的TableViewController調用,所以既然沒有奇怪的事情發生在這裏,我們可以安全地假設,如果顯示了一個警告,它必須明確地顯示在你的TableViewController上。所以一旦你關閉了警報或其他任何東西,你的TableViewController將繼續照常運作。儘管你會解僱你的TableViewController,但self會被釋放(因爲閉包被稱爲無主),但是到目前爲止,沒有辦法顯示這個alert。但是,如果你做了一些奇怪的事情,使得你的TableViewController被解散,但仍然顯示警報,那麼一旦用戶「提交」你的應用程序將崩潰。因爲通過聲明你的變量是無主的,你基本上對你的封閉做出承諾,即它不必擔心自我實體,因爲只要你的封閉還活着,它就一直存在。

+0

因此,基本上如果我們不放棄無主或弱,封閉內的屬性會受外面變化的影響?或者他們只是需要解除分配的目的...另外,viewController的所有屬性都有自己的引用,所以它們如何釋放。 –

+0

對不起,我很笨,我盡我所能。 –

+0

你在攪拌東西。無主或弱與外界修改無關。 OK,首先,括號[屬性]內的東西不會受外面發生的事情影響。其次,爲了取消分配目的,需要軟弱無主。避免保留週期。第三,viewController的所有屬性都由viewController本身保存,即「Self」。當viewcontroller被解除分配時,它們被釋放,當你解僱它時會發生這種情況。這與封閉無關,你只需確保封閉僅在VC存活時使用。 – Pochi

0

檢查了這一點。我創建了兩個同類的對象。其中一個引用了一個保留自身的閉包,所以即使創建該閉包的函數超出了範圍,該對象和閉包仍然保留在彼此之中,並且永遠不會被釋放。第二個對象的閉包有一個對該對象的弱引用,所以當對象創建函數超出作用域時,引用計數爲0,當它釋放時它也釋放閉包。

import UIKit 
import XCPlayground 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 

class B { 

    deinit { 
     print("\(name) deinit") 
    } 

    var name: String 

    init(name: String) { 
     self.name = name 
    } 
    var zort: (() ->())? 

    func someMethod() { 
     print("") 
    } 
} 

func createStuffThatNeverGoesAway() { 

    var b: B = B(name: "bad"); 
    b.zort = { 
     b.someMethod() 
    } 
} 

func createStuffThatGoesAway() { 

    var b: B = B(name: "good"); 
    b.zort = { [weak b] in 
     b?.someMethod() 
    } 
} 

createStuffThatNeverGoesAway() 
createStuffThatGoesAway() 

輸出:

good deinit