Mencetak variabel opsional

118

Saya mencoba dengan baris kode ini

class Student {
    var name: String
    var age: Int?

    init(name: String) {
        self.name = name
    }

    func description() -> String {
        return age != nil ? "\(name) is \(age) years old." : "\(name) hides his age."
    }
}

var me = Student(name: "Daniel")
println(me.description())
me.age = 18
println(me.description())

Hasil kode di atas adalah sebagai berikut

Daniel hides his age.
Daniel is Optional(18) years old.

Pertanyaan saya adalah mengapa ada Opsional (18) di sana, bagaimana saya bisa menghapus pilihan dan hanya mencetak

Daniel is 18 years old.
Daniel Adinugroho
sumber

Jawaban:

190

Anda harus memahami apa sebenarnya Opsional itu. Banyak pemula Swift yang berpikir var age: Int?bahwa usia adalah Int yang mungkin memiliki nilai atau tidak. Tetapi itu berarti bahwa usia adalah Opsional yang mungkin memiliki atau tidak memiliki Int.

Di dalam description()fungsi Anda, Anda tidak mencetak Int, melainkan Anda mencetak Opsional. Jika Anda ingin mencetak Int Anda harus membuka Opsional. Anda dapat menggunakan "pengikatan opsional" untuk membuka Opsional:

if let a = age {
 // a is an Int
}

Jika Anda yakin bahwa Opsional menampung objek, Anda dapat menggunakan "pembongkaran paksa":

let a = age!

Atau dalam contoh Anda, karena Anda sudah memiliki tes untuk nil di fungsi deskripsi, Anda bisa mengubahnya menjadi:

func description() -> String {
    return age != nil ? "\(name) is \(age!) years old." : "\(name) hides his age."
}
Apfelsaft
sumber
Saya pikir contoh ini akan sedikit lebih baik jika Anda mengubahnya menjadi menggunakanif let age = age { return ""} else { return "" }
kubi
13
+1 untuk:Many Swift beginners think var age: Int? means that age is an Int which may or may not have a value. But it means that age is an Optional which may or may not hold an Int.
lee
18

Sarana opsional bahwa Swift tidak sepenuhnya yakin apakah nilainya sesuai dengan tipe: misalnya, Int? artinya Swift tidak sepenuhnya yakin apakah bilangan tersebut adalah Int.

Untuk menghapusnya, ada tiga metode yang bisa Anda terapkan.

1) Jika Anda benar-benar yakin dengan jenisnya, Anda dapat menggunakan tanda seru untuk membukanya secara paksa, seperti ini:

// Here is an optional variable:

var age: Int?

// Here is how you would force unwrap it:

var unwrappedAge = age!

Jika Anda benar-benar membuka paksa sebuah opsional dan itu sama dengan nihil, Anda mungkin mengalami kesalahan crash ini:

masukkan deskripsi gambar di sini

Ini belum tentu aman, jadi berikut adalah metode yang mungkin mencegah error jika Anda tidak yakin dengan jenis dan nilainya:

Metode 2 dan tiga melindungi masalah ini.

2) Opsional yang Tidak Dibungkus Secara Implisit

 if let unwrappedAge = age {

 // continue in here

 }

Perhatikan bahwa tipe yang tidak dibungkus sekarang menjadi Int , bukan Int? .

3) Pernyataan penjaga

 guard let unwrappedAge = age else { 
   // continue in here
 }

Dari sini, Anda dapat melanjutkan dan menggunakan variabel yang tidak dibungkus. Pastikan hanya untuk membuka paksa (dengan!), Jika Anda yakin dengan jenis variabelnya.

Semoga berhasil dengan proyek Anda!

GJZ
sumber
1
menggunakan usia kembali! = nihil? "(nama) adalah (umur!) tahun." : "(nama) menyembunyikan usianya."
leedream
1
Menyelamatkan saya dari sakit kepala dengan masalah yang saya alami. Tidak bisa cukup berterima kasih.
Bruno Recillas
8

Untuk tujuan pengujian / debugging, saya sering ingin mengeluarkan opsional sebagai string tanpa harus selalu menguji nilnilai, jadi saya membuat operator kustom.

Saya meningkatkan banyak hal lebih jauh setelah membaca jawaban ini di pertanyaan lain .

fileprivate protocol _Optional {
    func unwrappedString() -> String
}

extension Optional: _Optional {
    fileprivate func unwrappedString() -> String {
        switch self {
        case .some(let wrapped as _Optional): return wrapped.unwrappedString()
        case .some(let wrapped): return String(describing: wrapped)
        case .none: return String(describing: self)
        }
    }
}

postfix operator ~? { }
public postfix func ~? <X> (x: X?) -> String {
    return x.unwrappedString
}

Tentunya operator (dan atributnya) dapat disesuaikan dengan keinginan Anda, atau Anda dapat menjadikannya sebagai fungsi. Bagaimanapun, ini memungkinkan Anda untuk menulis kode sederhana seperti ini:

var d: Double? = 12.34
print(d)     // Optional(12.34)
print(d~?)   // 12.34
d = nil
print(d~?)   // nil

Mengintegrasikan ide protokol orang lain membuatnya jadi ini bahkan berfungsi dengan opsional bersarang, yang sering terjadi saat menggunakan rangkaian opsional. Sebagai contoh:

let i: Int??? = 5
print(i)              // Optional(Optional(Optional(5)))
print("i: \(i~?)")    // i: 5
Jeremy
sumber
1
Pada Swift 3 Anda juga dapat menggunakan fungsi perpustakaan standar Swift debugPrint (_: separator: terminator :). Namun ini akan mencetak string dalam tanda kutip ganda.
psmythirl
@psmythirl: Senang mengetahuinya! Namun terkadang Anda mungkin hanya ingin melewatkan atau menyematkan opsional sebagai Stringtempat lain (misalnya pesan log / kesalahan).
Jeremy
print (d as Any)
DawnSong
7

Memperbarui

Cukup gunakan me.age ?? "Unknown age!". Ia bekerja di 3.0.2.

Jawaban Lama

Tanpa paksa membuka bungkus (tidak ada sinyal mach / crash jika nihil) cara lain yang bagus untuk melakukan ini adalah:

(result["ip"] ?? "unavailable").description.

result["ip"] ?? "unavailable" seharusnya bekerja juga, tetapi tidak, setidaknya tidak di 2.2

Tentu saja, ganti "tidak tersedia" dengan apa pun yang cocok untuk Anda: "nil", "tidak ditemukan" dll

Valentin Radu
sumber
4

Untuk membuka bungkus penggunaan opsional, age!bukan age. Saat ini Anda sedang mencetak nilai opsional yang bisa nil. Itulah mengapa dibungkus dengan Optional.

Kirstein
sumber
4

Dalam sekejap Optionaladalah sesuatu yang nildalam beberapa kasus. Jika Anda 100% yakin bahwa a variableakan selalu memiliki beberapa nilai dan tidak akan mengembalikan nilpenambahan !dengan variabel untuk membukanya secara paksa.

Dalam kasus lain jika Anda tidak terlalu yakin dengan nilainya maka tambahkan if letblok atau guarduntuk memastikan bahwa nilai itu ada, jika tidak maka dapat mengakibatkan crash.

Untuk if letblok:

if let abc = any_variable {
 // do anything you want with 'abc' variable no need to force unwrap now.
}

Untuk guardpernyataan:

guard adalah struktur bersyarat untuk mengembalikan kontrol jika kondisi tidak terpenuhi.

Saya lebih suka menggunakan guardover if letblock dalam banyak situasi karena memungkinkan kita untuk mengembalikan functionjika nilai tertentu tidak ada. Seperti ketika ada fungsi di mana variabel integral ada, kita bisa memeriksanya di pernyataan penjaga dan mengembalikannya tidak ada. yaitu;

guard let abc = any_variable else { return }

Kami jika ada variabel, kami dapat menggunakan 'abc' dalam fungsi di luar lingkup penjaga.

Muhammad Yawar Ali
sumber
3

ageadalah tipe opsional: Optional<Int>jadi jika Anda membandingkannya dengan nil, ia mengembalikan false setiap kali memiliki nilai atau jika belum. Anda perlu membuka opsional untuk mendapatkan nilainya.

Dalam contoh Anda, Anda tidak tahu apakah itu berisi nilai apa pun sehingga Anda dapat menggunakan ini sebagai gantinya:

if let myAge = age {
    // there is a value and it's currently undraped and is stored in a constant
}
else {
   // no value
}
Greg
sumber
3

Saya melakukan ini untuk mencetak nilai string (properti) dari pengontrol tampilan lain.

ViewController.swift

var testString:NSString = "I am iOS Developer"

SecondViewController.swift

var obj:ViewController? = ViewController(nibName: "ViewController", bundle: nil)
print("The Value of String is \(obj!.testString)")

Hasil:

The Value of String is I am iOS Developer
iCodeAtApple
sumber
2
Anda tidak boleh memaksa membuka
bungkus
3

Lihat guardpernyataannya:

for student in class {
    guard let age = student.age else { 
        continue 
     }
    // do something with age
}
Phil Hudson
sumber
3

Saat memiliki nilai default:

print("\(name) is \(age ?? 0) years old")

atau jika namanya opsional:

print("\(name ?? "unknown") is \(age) years old")

arnon
sumber
1

Saya mendapatkan Opsional ("String") di sel tampilan tabel saya.

Jawaban pertama bagus. Dan membantuku mengetahuinya. Inilah yang saya lakukan, untuk membantu pemula di luar sana seperti saya.

Karena saya membuat array di objek khusus saya, saya tahu bahwa itu akan selalu memiliki item di posisi pertama, jadi saya bisa memaksa membukanya ke variabel lain. Kemudian gunakan variabel itu untuk mencetak, atau dalam kasus saya, setel ke teks sel tampilan tabel.

let description = workout.listOfStrings.first!
cell.textLabel?.text = description

Kelihatannya sangat sederhana sekarang, tapi butuh beberapa saat untuk saya pikirkan.

Joshua Dance
sumber
-1

Ini bukanlah jawaban yang tepat untuk pertanyaan ini, tetapi satu alasan untuk masalah seperti ini. Dalam kasus saya, saya tidak dapat menghapus Opsional dari String dengan "if let" dan "guard let".

Jadi gunakan AnyObject daripada Any untuk menghapus opsional dari string dengan cepat.

Silakan lihat link untuk jawabannya.

https://stackoverflow.com/a/51356716/8334818

Pramod Lebih
sumber