Bagaimana menjaga penugasan variabel yang ada tanpa let/var di Swift 2

Kata kunci guard luar biasa dan saya telah menggunakannya sejak Swift 2 diluncurkan. Saya berhasil menggunakannya dalam banyak skenario, termasuk yang ini:

for viewController in self.navigationController!.viewControllers {
    guard let myCustomVC = viewController as? MyCustomViewController else {continue}

    myCustomVC.doWhatItHasToDo()
    break
}

Bekerja seperti pesona. Ulangi semua viewControllers di navigationController saat ini hingga menemukan yang saya inginkan.

Masalahnya adalah: sekarang saya perlu memperbarui kode di atas untuk menggunakan kembali variabel myCustomVC di luar cakupan for..in. Seharusnya sesederhana mendeklarasikan variabel sebelum cakupan, tetapi saya tidak dapat menemukan cara untuk guard penugasan variabel tanpa kata kunci let atau var.

Kode hipotetis berikut menunjukkan apa yang ingin saya capai, namun Swift tidak mengizinkan saya melakukannya:

var myCustomVC: MyCustomViewController
for viewController in self.navigationController!.viewControllers {
    guard myCustomVC = viewController as? MyCustomViewController else {continue}

    myCustomVC.doWhatItHasToDo()
    break
}

// Now myCustomVC is available outside the for...in scope
myCustomVC.doWhatever()

Xcode menyarankan penggunaan == daripada = karena mengharapkan pernyataan guard menjadi konteks boolean dan bukan penetapan variabel.

Kesalahan Xcode

Adakah ide tentang cara mengatasi masalah ini?


person mathielo    schedule 18.12.2015    source sumber
comment
Bisakah Anda menggunakan filter untuk menemukan pengontrol yang Anda inginkan?   -  person Michael Welch    schedule 19.12.2015
comment
let myCustomVC = viewControllers.filter { /* letakkan predikat di sini */ }.first; myCustomVC.doWhatItHasToDo(); myCustomVC.doWhatever();   -  person Michael Welch    schedule 19.12.2015


Jawaban (2)


Maafkan saya karena tidak menjawab pertanyaan Anda. Saya rasa apa yang Anda tanyakan tidak mungkin. Tapi saya punya alternatif.

Sepertinya Anda berulang kali menulis metode filter secara manual. Saya sarankan menggunakan filter saja untuk menemukan elemen yang Anda inginkan. Jika lebih dari satu yang cocok, gunakan first untuk mengambil yang pertama. Misalnya, di bawah ini saya memilih bilangan genap pertama dari daftar:

let myArray = [0,1,3,5,7,4,6,10,11]
let myNum = myArray.filter { $0 % 2 == 0 }.first

Saya tidak tahu sintaks pasti yang digunakan untuk predikat Anda, tetapi kira-kira seperti berikut

let myCustomVC = self.navigationController!.viewControllers.filter {
    $0 is MyCustomViewController }.first

// myCustomVC will be an optional because first returns an optional
if let myCustomVC = myCustomVC {
    myCustomVC.doWhatItHasToDo()
    myCustomVC.doWhatever()
}

Atau jika Anda memiliki tindakan untuk dilakukan pada setiap elemen yang cocok dengan predikatnya, gunakan foreach

    let myCustomVC = self.navigationController!.viewControllers.filter {
    $0 is MyCustomViewController }.foreach { // action // }
person Michael Welch    schedule 18.12.2015
comment
Jawaban super Michael! Terima kasih atas penjelasan mendetail dan contoh luar biasa. Memang saya menemukan kembali roda tanpa menyadarinya. - person mathielo; 19.12.2015
comment
Dingin. Senang ini memenuhi kebutuhan Anda - person Michael Welch; 19.12.2015

Saya terus memikirkan pertanyaan Anda. Dimungkinkan untuk melakukan apa yang awalnya Anda minta, namun solusi yang saya temukan agak berbelit-belit. Pada dasarnya ini melibatkan pendefinisian penutupan tipe Any -> Bool yang dapat Anda gunakan dalam pernyataan penjaga Anda. Berikut contoh lengkapnya. Mungkin jika ini berguna Anda bisa membersihkannya. Perulangan for sebenarnya tidak buruk, dengan asumsi penutupan predikat Anda sudah ditentukan di suatu tempat.

class MyClass {}

var myCollection = [Any]()
// add sample elements 
myCollection.append("hello")
myCollection.append(MyClass())

// declare the variable to receive the "found" element
var myElement:MyClass? = nil

// define our predicate to use in guard statement
let myPredicate:Any->Bool = { obj in
    if let obj = obj as? MyClass {
        myElement = obj
        return true
    }
    return false
}

for v in myCollection {
    guard myPredicate(v)
    else {continue}

   // do something with v
}

if let myElement = myElement {
    print(myElement)
}

UPDATE: Contoh yang lebih sederhana (masih memerlukan let)

for v in myCollection {
    guard let myObj = v as? MyClass else {continue}
    myElement = myObj
}
person Michael Welch    schedule 19.12.2015