Xcode 8 / Swift 3: “Ekspresi tipe UIViewController? tidak digunakan ”peringatan

230

Saya punya fungsi berikut yang dikompilasi dengan bersih sebelumnya tetapi menghasilkan peringatan dengan Xcode 8.

func exitViewController()
{
    navigationController?.popViewController(animated: true)
}

"Ekspresi tipe" UIViewController? "Tidak digunakan".

Mengapa dikatakan demikian dan adakah cara untuk menghapusnya?

Kode dijalankan seperti yang diharapkan.

Gruntcakes
sumber

Jawaban:

498

TL; DR

popViewController(animated:)kembali UIViewController?, dan kompilator memberikan peringatan itu karena Anda tidak menangkap nilainya. Solusinya adalah dengan menetapkannya ke garis bawah:

_ = navigationController?.popViewController(animated: true)

Swift 3 Perubahan

Sebelum Swift 3, semua metode memiliki "hasil yang dapat dibuang" secara default. Tidak ada peringatan yang akan terjadi jika Anda tidak menangkap apa yang dikembalikan metode tersebut.

Untuk memberi tahu compiler bahwa hasilnya harus diambil, Anda harus menambahkan @warn_unused_resultsebelum deklarasi metode. Ini akan digunakan untuk metode yang memiliki bentuk yang bisa berubah (mis. sortDan sortInPlace). Anda akan menambahkan @warn_unused_result(mutable_variant="mutableMethodHere")untuk memberi tahu kompilernya.

Namun, dengan Swift 3, perilakunya terbalik. Semua metode sekarang memperingatkan bahwa nilai yang dikembalikan tidak ditangkap. Jika Anda ingin memberi tahu compiler bahwa peringatan tersebut tidak diperlukan, Anda menambahkan @discardableResultsebelum deklarasi metode.

Jika Anda tidak ingin menggunakan nilai yang dikembalikan, Anda harus memberi tahu compiler secara eksplisit dengan menetapkannya ke garis bawah:

_ = someMethodThatReturnsSomething()

Motivasi untuk menambahkan ini ke Swift 3:

  • Pencegahan kemungkinan bug (mis. Menggunakan sortpemikiran itu memodifikasi koleksi)
  • Maksud eksplisit untuk tidak menangkap atau perlu menangkap hasil untuk kolaborator lain

UIKit API tampaknya tertinggal dalam hal ini, tidak menambahkan @discardableResultuntuk penggunaan normal sempurna (jika tidak lebih umum) popViewController(animated:)tanpa menangkap nilai yang dikembalikan.

Baca lebih banyak

tktsubota.dll
sumber
15
Ini adalah (menurut saya) pasti kembali langkah dari Swift 2, terutama bila ada metode seperti ini yang, meskipun mereka melakukan mengembalikan nilai, ada kasus penggunaan sempurna berlaku di mana Anda hanya tidak menggunakannya.
Nicolas Miari
15
1. Anda tidak memerlukan let: Anda bisa menetapkan ke _ tanpa mendahului dengan letatau var.
rickster
1
@rickster Tidak tahu itu akan menambah jawaban.
tktsubota
5
2. @NicolasMiari Laporkan bug . Ada annotation ( @discardableResult) untuk fungsi yang mengembalikan nilai tetapi diharapkan seseorang dapat mengabaikan nilai yang dikembalikan. UIKit belum menerapkan anotasi itu ke API mereka.
rickster
37
Ini sintaks yang mengerikan. Mengapa mereka melakukan ini? Yuck.
David S.
38

Saat kehidupan memberi Anda lemon, buat perpanjangan:

import UIKit

extension UINavigationController {
    func pop(animated: Bool) {
        _ = self.popViewController(animated: animated)
    }

    func popToRoot(animated: Bool) {
        _ = self.popToRootViewController(animated: animated)
    }
}

Perhatikan bahwa menambahkan sesuatu seperti @discardableResult func pop(animated: Bool) -> UIViewController?akan menghasilkan peringatan yang sama dengan yang Anda coba hindari.

Dengan ekstensi sekarang Anda dapat menulis:

func exitViewController()
{
    navigationController?.pop(animated: true)
}

func popToTheRootOfNav() {
    navigationController?.popToRoot(animated: true)
}

Edit: Menambahkan popToRoot juga.

CodeReaper
sumber
Ini harus menjadi solusi yang diterima karena ini adalah perbaikan terbersih untuk apa yang pasti akan diperbaiki dalam pembaruan Xcode.
Philip Broadway
24

Di Swift 3, mengabaikan nilai kembalian dari suatu fungsi yang memiliki nilai kembalian yang dideklarasikan akan menghasilkan peringatan.

Salah satu cara untuk menyisih dari ini adalah menandai fungsi dengan @discardableResultatribut. Karena Anda tidak memiliki kendali atas fungsi ini, itu tidak akan berhasil.

Metode lain untuk menghilangkan peringatan adalah dengan menetapkan nilainya _. Ini memberi tahu kompiler bahwa Anda tahu metode tersebut mengembalikan nilai tetapi Anda tidak ingin menyimpannya dalam memori.

let _ = navigationController?.popViewController(animated: true)
Matthew Seaman
sumber
2
Saya kira kita harus bertahan dengan yang jelek _sampai Apple memperbarui UIKit dengan atribut baru ini.
Nicolas Miari
2
Sayangnya @discardableResulttidak berhasil (setidaknya masih serak dengan 8b4). Friedrich Schiller menyukai apel busuk. Mungkin masalah selera :-(
qwerty_so
5

Tangkapan layar 1

Meskipun itu work correctly if kept as it istapinumber of warning increases.

Solusinya adalah dengan sederhana replace it with underscore ( _ )meskipun tampaknya jelek.

Eg.  _ = navigationController?.popViewController(animated: true)

Tangkapan layar 2

Jayprakash Dubey
sumber
2

Gunakan discardableResult dalam kondisi ini.

Menurut <Swift Programming Language>, bab Referensi Bahasa - Atribut.

discardableResult

Terapkan atribut ini ke deklarasi fungsi atau metode untuk menekan peringatan compiler ketika fungsi atau metode yang mengembalikan nilai dipanggil tanpa menggunakan hasilnya.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Attributes.html#//apple_ref/doc/uid/TP40014097-CH35-ID347

Ada juga demo dalam <Swift Programming Language>, bab Panduan Bahasa - Metode.

@discardableResult
    mutating func advance(to level: Int) -> Bool {
    ...
return true
}

Karena tidak selalu merupakan kesalahan untuk kode yang memanggil metode advance (to :) untuk mengabaikan nilai yang dikembalikan, fungsi ini ditandai dengan atribut @discardableResult. Untuk informasi lebih lanjut tentang atribut ini, lihat Atribut.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html#//apple_ref/doc/uid/TP40014097-CH15-ID234

Mutiara Hitam
sumber
0

Jika Anda ingin menggunakan ekstensi seperti jawaban CodeReaper, Anda harus menggunakan @descardableResult. Ini menyimpan semua kemungkinan, tetapi membungkam peringatan.

import UIKit

extension UINavigationController {
    @discardableResult func pop(animated: Bool) -> UIViewController? {
        return self.popViewController(animated: animated)
    }

    @discardableResult func popToRoot(animated: Bool) -> [UIViewController]? {
        return self.popToRootViewController(animated: animated)
    }
}
Casper Zandbergen
sumber
-1

Cara lain adalah Anda dapat membuka bungkus self.navigationController?nilai dan memanggil popViewControllerfungsinya.

    if let navigationController = navigationController {
        navigationController.popViewController(animated: true)
    }
muazhud
sumber