Penanganan Kesalahan dalam Bahasa Swift

190

Saya belum banyak membaca Swift tetapi satu hal yang saya perhatikan adalah tidak ada pengecualian. Jadi bagaimana mereka melakukan penanganan kesalahan di Swift? Adakah yang menemukan sesuatu yang berhubungan dengan penanganan kesalahan?

peko
sumber
1
Saya menemukan pesan kesalahan seperti pada Obj-C: o
Arbitur
13
@ Arbitur cara segfault tua yang bagus?
peko
Membuat NSTimer di Swift dan ketika saya salah mengeja fungsi itu macet dan memberi saya kesalahan mengatakan tidak dapat menemukan metode :)
Arbitur
3
Anda dapat menambahkan dukungan coba-coba untuk Swift dengan mengikuti petunjuk di artikel ini: medium.com/@_willfalcon/adding-try-catch-to-swift-71ab27bcb5b8
William Falcon
@ peko Bagaimana Anda menangani segfault di Swift? Saya tidak berpikir itu mungkin sampai sekarang, yang sayangnya membuat beberapa kesalahan tidak dapat dipulihkan
Orlin Georgiev

Jawaban:

148

Swift 2 & 3

Banyak hal telah berubah sedikit di Swift 2, karena ada mekanisme penanganan kesalahan baru, yang agak lebih mirip dengan pengecualian tetapi berbeda dalam detailnya.

1. Menunjukkan kemungkinan kesalahan

Jika fungsi / metode ingin menunjukkan bahwa ia dapat menimbulkan kesalahan, itu harus mengandung throwskata kunci seperti ini

func summonDefaultDragon() throws -> Dragon

Catatan: tidak ada spesifikasi untuk jenis kesalahan yang dapat dilemparkan oleh fungsi tersebut. Deklarasi ini hanya menyatakan bahwa fungsi tersebut dapat melempar instance dari jenis apa pun yang menerapkan ErrorType atau tidak melempar sama sekali.

2. Memohon fungsi yang dapat menyebabkan kesalahan

Untuk menjalankan fungsi, Anda perlu menggunakan kata kunci coba, seperti ini

try summonDefaultDragon()

baris ini biasanya harus ada blok do-catch seperti ini

do {
    let dragon = try summonDefaultDragon() 
} catch DragonError.dragonIsMissing {
    // Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
    // Other specific-case error-handlng
} catch {
    // Catch all error-handling
}

Catatan: catch clause menggunakan semua fitur canggih pencocokan pola Swift sehingga Anda sangat fleksibel di sini.

Anda dapat memutuskan untuk menyebarkan kesalahan, jika Anda memanggil fungsi melempar dari fungsi yang ditandai dengan throwskata kunci:

func fulfill(quest: Quest) throws {
    let dragon = try summonDefaultDragon()
    quest.ride(dragon)
} 

Atau, Anda dapat memanggil fungsi melempar menggunakan try?:

let dragonOrNil = try? summonDefaultDragon()

Dengan cara ini Anda mendapatkan nilai kembali atau nihil, jika terjadi kesalahan. Dengan menggunakan cara ini Anda tidak mendapatkan objek kesalahan.

Yang berarti Anda juga dapat menggabungkan try?dengan pernyataan berguna seperti:

if let dragon = try? summonDefaultDragon()

atau

guard let dragon = try? summonDefaultDragon() else { ... }

Akhirnya, Anda dapat memutuskan bahwa Anda tahu bahwa kesalahan tidak akan benar-benar terjadi (misalnya karena Anda telah memeriksa prasyarat) dan menggunakan try!kata kunci:

let dragon = try! summonDefaultDragon()

Jika fungsi tersebut benar-benar melempar kesalahan, maka Anda akan mendapatkan kesalahan runtime di aplikasi Anda dan aplikasi akan berakhir.

3. Melempar kesalahan

Untuk melempar kesalahan, Anda menggunakan kata kunci melempar seperti ini

throw DragonError.dragonIsMissing

Anda dapat membuang apa pun yang sesuai dengan ErrorTypeprotokol. Sebagai permulaan NSErrorsesuai dengan protokol ini, tetapi Anda mungkin ingin menggunakan berbasis enum ErrorTypeyang memungkinkan Anda untuk mengelompokkan beberapa kesalahan terkait, berpotensi dengan potongan data tambahan, seperti ini

enum DragonError: ErrorType {
    case dragonIsMissing
    case notEnoughMana(requiredMana: Int)
    ...
}

Perbedaan utama antara mekanisme kesalahan Swift 2 & 3 baru dan pengecualian gaya Java / C # / C ++ adalah sebagai berikut:

  • Sintaksnya sedikit berbeda: do-catch+ try+ defervs try-catch-finallysintaksis tradisional .
  • Penanganan pengecualian biasanya menimbulkan waktu eksekusi yang jauh lebih tinggi di jalur pengecualian daripada di jalur sukses. Ini tidak terjadi dengan kesalahan Swift 2.0, di mana jalur keberhasilan dan jalur kesalahan harganya kira-kira sama.
  • Semua kode melempar kesalahan harus dideklarasikan, sementara pengecualian mungkin dilemparkan dari mana saja. Semua kesalahan adalah "pengecualian yang diperiksa" dalam nomenklatur Java. Namun, berbeda dengan Java, Anda tidak menentukan kesalahan yang berpotensi terjadi.
  • Pengecualian cepat tidak kompatibel dengan pengecualian ObjC. do-catchBlok Anda tidak akan menangkap NSException, dan sebaliknya, untuk itu Anda harus menggunakan ObjC.
  • Pengecualian cepat kompatibel dengan NSErrorkonvensi metode Kakao untuk mengembalikan false(untuk Boolfungsi kembali) atau nil(untuk AnyObjectfungsi kembali) dan meneruskan NSErrorPointerdengan detail kesalahan.

Sebagai tambahan sintaksis-gula untuk memudahkan penanganan kesalahan, ada dua konsep lagi

  • tindakan yang ditangguhkan (menggunakan deferkata kunci) yang memungkinkan Anda mencapai efek yang sama dengan akhirnya memblokir di Java / C # / etc
  • pernyataan penjaga (menggunakan guardkata kunci) yang memungkinkan Anda menulis kode if / else lebih sedikit dari pada kode pengecekan / pensinyalan kesalahan normal.

Cepat 1

Kesalahan runtime:

Seperti yang disarankan Leandros untuk menangani kesalahan runtime (seperti masalah konektivitas jaringan, parsing data, file pembukaan, dll) Anda harus menggunakan NSErrorseperti yang Anda lakukan di ObjC, karena Foundation, AppKit, UIKit, dll melaporkan kesalahan mereka dengan cara ini. Jadi lebih banyak hal kerangka daripada hal bahasa.

Pola lain yang sering digunakan adalah blok sukses / gagal pemisah seperti di AFNetworking:

var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
    success: { (NSURLSessionDataTask) -> Void in
        println("Success")
    },
    failure:{ (NSURLSessionDataTask, NSError) -> Void in
        println("Failure")
    })

Masih blok kegagalan sering diterima NSErrorcontoh, menggambarkan kesalahan.

Kesalahan pemrogram:

Untuk kesalahan programmer (seperti akses di luar batas elemen array, argumen tidak valid diteruskan ke panggilan fungsi, dll) Anda menggunakan pengecualian di ObjC. Bahasa Swift tampaknya tidak memiliki dukungan bahasa untuk pengecualian (seperti throw, catch, dll kata kunci). Namun, seperti yang ditunjukkan oleh dokumentasi, ia menjalankan runtime yang sama dengan ObjC, dan karenanya Anda masih dapat melempar NSExceptionsseperti ini:

NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()

Anda tidak dapat menangkapnya dalam Swift murni, meskipun Anda dapat memilih untuk menangkap pengecualian dalam kode ObjC.

Pertanyaannya adalah apakah Anda harus melempar pengecualian untuk kesalahan programmer, atau lebih tepatnya menggunakan pernyataan seperti yang disarankan Apple dalam panduan bahasa.

MDJ
sumber
20
"masalah konektivitas jaringan" dan "membuka file" menggunakan API Kakao (NSFileHandle) dapat membuang pengecualian yang perlu ditangkap. Tanpa pengecualian di Swift, Anda perlu mengimplementasikan bagian program Anda ini di Objective-C atau melakukan semua pekerjaan Anda menggunakan API BSD C (keduanya merupakan solusi yang buruk). Lihat dokumentasi untuk NSFileHandle.writeData untuk lebih lanjut ... developer.apple.com/library/ios/documentation/Cocoa/Reference/… :
Matt Gallagher
5
Sekali lagi, tidak terkecuali penanganan berarti pembangunan objek dua tahap dengan semua masalah yang melekat. Lihat stroustrup.com/except.pdf .
Phil
2
yang fatalError(...)sama juga.
holex
8
Seperti saya suka Swift, saya pikir ini adalah pilihan bencana, dan setelah merasakan beberapa konsekuensi, mereka bermain api dengan kelalaian ini ...
Rob
2
Ya, pengecualian diperiksa sekarang digunakan hemat, karena ditemukan bahwa memaksa programmer untuk menangkap pengecualian mereka memiliki sedikit harapan untuk pulih dari kode polusi dalam cara melanggar prinsip tanggung jawab tunggal. Kelas tingkat domain tidak mau harus berurusan dengan pengecualian lapisan infrastruktur. Jadi sekarang, pengecualian yang tidak dicentang cenderung disukai, dan pihak yang berkepentingan dapat menangkapnya, jika perlu. . Dicentang = pasti dapat dipulihkan. Tidak dicentang = tidak berpotensi dipulihkan.
Jasper Blues
69

Perbarui 9 Juni 2015 - Sangat penting

Swift 2.0 hadir dengan try,, throwdan catchkata kunci dan yang paling menarik adalah:

Swift secara otomatis menerjemahkan metode Objective-C yang menghasilkan kesalahan ke dalam metode yang melempar kesalahan sesuai dengan fungsionalitas penanganan kesalahan asli Swift.

Catatan: Metode yang menggunakan kesalahan, seperti metode mendelegasikan atau metode yang mengambil penangan penyelesaian dengan argumen objek NSError, jangan menjadi metode yang melempar ketika diimpor oleh Swift.

Kutipan dari: Apple Inc. “Menggunakan Swift dengan Kakao dan Objective-C (Swift 2 Prerelease).” iBooks.

Contoh: (dari buku)

NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success && error){
    NSLog(@"Error: %@", error.domain);
}

Setara dengan swift adalah:

let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("path/to/file")
do {
    try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
    print ("Error: \(error.domain)")
}

Melempar Kesalahan:

*errorPtr = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotOpenFile userInfo: nil]

Akan secara otomatis disebarkan ke penelepon:

throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)

Dari buku-buku Apple, The Swift Programming Language, tampaknya kesalahan harus ditangani menggunakan enum.

Ini adalah contoh dari buku ini.

enum ServerResponse {
    case Result(String, String)
    case Error(String)
}

let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")

switch success {
case let .Result(sunrise, sunset):
    let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
    let serverResponse = "Failure...  \(error)"
}

Dari: Apple Inc. "Bahasa Pemrograman Swift." iBooks. https://itun.es/br/jEUH0.l

Memperbarui

Dari buku-buku berita Apple, "Menggunakan Swift dengan Kakao dan Objective-C". Pengecualian runtime tidak terjadi menggunakan bahasa cepat, jadi itu sebabnya Anda tidak memiliki try-catch. Sebagai gantinya Anda menggunakan Chaining Opsional .

Ini adalah peregangan dari buku ini:

Misalnya, dalam daftar kode di bawah ini, baris pertama dan kedua tidak dieksekusi karena properti panjang dan metode characterAtIndex: tidak ada pada objek NSDate. Konstanta myLength disimpulkan sebagai Int opsional, dan diatur ke nol. Anda juga dapat menggunakan pernyataan if-let untuk membukanya secara kondisional dari suatu metode yang objeknya mungkin tidak merespons, seperti yang ditunjukkan pada baris tiga

let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
    println("Found \(fifthCharacter) at index 5")
}

Kutipan dari: Apple Inc. “Menggunakan Swift dengan Kakao dan Objective-C.” iBooks. https://itun.es/br/1u3-0.l


Dan buku-buku itu juga mendorong Anda untuk menggunakan pola kesalahan kakao dari Objective-C (NSError Object)

Pelaporan kesalahan di Swift mengikuti pola yang sama dengan yang dilakukan di Objective-C, dengan manfaat tambahan dari menawarkan nilai pengembalian opsional. Dalam kasus paling sederhana, Anda mengembalikan nilai Bool dari fungsi untuk menunjukkan apakah itu berhasil atau tidak. Saat Anda perlu melaporkan alasan kesalahan, Anda dapat menambahkan ke fungsi parameter NSError out dari tipe NSErrorPointer. Jenis ini kira-kira setara dengan NSError Objective-C **, dengan keamanan memori tambahan dan pengetikan opsional. Anda dapat menggunakan awalan & operator untuk meneruskan referensi ke jenis NSError opsional sebagai objek NSErrorPointer, seperti yang ditunjukkan dalam daftar kode di bawah ini.

var writeError : NSError?
let written = myString.writeToFile(path, atomically: false,
    encoding: NSUTF8StringEncoding,
    error: &writeError)
if !written {
    if let error = writeError {
        println("write failure: \(error.localizedDescription)")
    }
}

Kutipan dari: Apple Inc. “Menggunakan Swift dengan Kakao dan Objective-C.” iBooks. https://itun.es/br/1u3-0.l

Guilherme Torres Castro
sumber
Untuk pernyataan terakhir, seharusnya: do {coba myString.writeToFile (path, atomically: true, encoding: NSUTF8StringEncoding)} catch error let sebagai NSError {print (error)}
Jacky
1
@ Jacky Ya, itu berlaku untuk swift 2.0 meskipun jawaban ini ditulis sebelum rilis swift 2.0, saya memperbarui jawaban untuk menunjukkan cara baru menangani kesalahan di swift 2.0. Saya berpikir untuk membiarkan referensi seperti ini, tetapi saya akan mempertimbangkan memperbarui seluruh jawaban untuk menggunakan hanya swift 2.0
Guilherme Torres Castro
12

Tidak ada Pengecualian di Swift, mirip dengan pendekatan Objective-C.

Dalam pengembangan, Anda dapat menggunakan assertuntuk menangkap kesalahan yang mungkin muncul, dan perlu diperbaiki sebelum mulai berproduksi.

NSErrorPendekatan klasik tidak diubah, Anda mengirim NSErrorPointer, yang akan diisi.

Contoh singkat:

var error: NSError?
var contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/Users/leandros", error: &error)
if let error = error {
    println("An error occurred \(error)")
} else {
    println("Contents: \(contents)")
}
Leandros
sumber
6
Ini menimbulkan dua pertanyaan: apa yang terjadi ketika kode ObjC yang kita panggil dari Swift benar-benar melempar pengecualian, dan apakah NSError adalah objek kesalahan universal kita seperti di ObjC?
MDJ
1
Apakah hanya fakta kehidupan dengan Swift yang tidak diinisialisasi oleh inisialisasi atau gagal?
Phil
11
Penanganan pengecualian tampak agak kotor
Tash Pemhiwa
27
Ya, siapa yang butuh pengecualian ketika Anda bisa saja crash? Atau letakkan NSError ** sebagai argumen di semua fungsi yang Anda nyatakan? sehingga setiap f();g();menjadi f(&err);if(err) return;g(&err);if(err) return;untuk bulan pertama, maka itu hanya menjadif(nil);g(nil);hopeToGetHereAlive();
hariseldon78
2
Jawaban ini kedaluwarsa (Swift sekarang mendukung pengecualian) dan salah (Objective-C mendukung pengecualian.
Rog
11

'Swift Way' yang disarankan adalah:

func write(path: String)(#error: NSErrorPointer) -> Bool { // Useful to curry error parameter for retrying (see below)!
    return "Hello!".writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: error)
}

var writeError: NSError?
let written = write("~/Error1")(error: &writeError)
if !written {
    println("write failure 1: \(writeError!.localizedDescription)")
    // assert(false) // Terminate program
}

Namun saya lebih suka mencoba / menangkap karena saya merasa lebih mudah untuk mengikuti karena memindahkan penanganan kesalahan ke blok yang terpisah di akhir, pengaturan ini kadang-kadang disebut "Jalur Emas". Beruntung Anda bisa melakukan ini dengan penutupan:

TryBool {
    write("~/Error2")(error: $0) // The code to try
}.catch {
    println("write failure 2: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

Juga mudah untuk menambahkan fasilitas coba lagi:

TryBool {
    write("~/Error3")(error: $0) // The code to try
}.retry {
    println("write failure 3 on try \($1 + 1): \($0!.localizedDescription)")
    return write("~/Error3r")  // The code to retry
}.catch {
    println("write failure 3 catch: \($0!.localizedDescription)") // Report failure
    // assert(false) // Terminate program
}

Daftar untuk TryBool adalah:

class TryBool {
    typealias Tryee = NSErrorPointer -> Bool
    typealias Catchee = NSError? -> ()
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return self.retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) {
        var error: NSError?
        for numRetries in 0...retries { // First try is retry 0
            error = nil
            let result = tryee(&error)
            if result {
                return
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        catchee(error)
    }
}

Anda dapat menulis kelas serupa untuk menguji nilai yang dikembalikan opsional dan bukan nilai Bool:

class TryOptional<T> {
    typealias Tryee = NSErrorPointer -> T?
    typealias Catchee = NSError? -> T
    typealias Retryee = (NSError?, UInt) -> Tryee

    private var tryee: Tryee
    private var retries: UInt = 0
    private var retryee: Retryee?

    init(tryee: Tryee) {
        self.tryee = tryee
    }

    func retry(retries: UInt, retryee: Retryee) -> Self {
        self.retries = retries
        self.retryee = retryee
        return self
    }
    func retry(retryee: Retryee) -> Self {
        return retry(1, retryee)
    }
    func retry(retries: UInt) -> Self {
        // For some reason you can't write the body as "return retry(1, nil)", the compiler doesn't like the nil
        self.retries = retries
        retryee = nil
        return self
    }
    func retry() -> Self {
        return retry(1)
    }

    func catch(catchee: Catchee) -> T {
        var error: NSError?
        for numRetries in 0...retries {
            error = nil
            let result = tryee(&error)
            if let r = result {
                return r
            } else if numRetries != retries {
                if let r = retryee {
                    tryee = r(error, numRetries)
                }
            }
        }
        return catchee(error)
    }
}

Versi TryOptional memberlakukan jenis pengembalian non-opsional yang membuat pemrograman berikutnya lebih mudah, misalnya 'Swift Way:

struct FailableInitializer {
    init?(_ id: Int, error: NSErrorPointer) {
        // Always fails in example
        if error != nil {
            error.memory = NSError(domain: "", code: id, userInfo: [:])
        }
        return nil
    }
    private init() {
        // Empty in example
    }
    static let fallback = FailableInitializer()
}

func failableInitializer(id: Int)(#error: NSErrorPointer) -> FailableInitializer? { // Curry for retry
    return FailableInitializer(id, error: error)
}

var failError: NSError?
var failure1Temp = failableInitializer(1)(error: &failError)
if failure1Temp == nil {
    println("failableInitializer failure code: \(failError!.code)")
    failure1Temp = FailableInitializer.fallback
}
let failure1 = failure1Temp! // Unwrap

Menggunakan TryOptional:

let failure2 = TryOptional {
    failableInitializer(2)(error: $0)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

let failure3 = TryOptional {
    failableInitializer(3)(error: $0)
}.retry {
    println("failableInitializer failure, on try \($1 + 1), code: \($0!.code)")
    return failableInitializer(31)
}.catch {
    println("failableInitializer failure code: \($0!.code)")
    return FailableInitializer.fallback
}

Catatan buka otomatis.

Howard Lovatt
sumber
7

Edit: Walaupun jawaban ini berhasil, ini lebih dari Objective-C yang ditransliterasikan ke dalam Swift. Itu telah dibuat usang oleh perubahan dalam Swift 2.0. Jawaban Guilherme Torres Castro di atas adalah pengantar yang sangat bagus untuk cara penanganan kesalahan yang disukai di Swift. VOS

Butuh sedikit mencari tahu tapi saya pikir saya sudah sussed itu. Sepertinya jelek. Tidak lebih dari kulit tipis di atas versi Objective-C.

Memanggil fungsi dengan parameter NSError ...

var fooError : NSError ? = nil

let someObject = foo(aParam, error:&fooError)

// Check something was returned and look for an error if it wasn't.
if !someObject {
   if let error = fooError {
      // Handle error
      NSLog("This happened: \(error.localizedDescription)")
   }
} else {
   // Handle success
}`

Menulis fungsi yang mengambil parameter kesalahan ...

func foo(param:ParamObject, error: NSErrorPointer) -> SomeObject {

   // Do stuff...

   if somethingBadHasHappened {
      if error {
         error.memory = NSError(domain: domain, code: code, userInfo: [:])
      }
      return nil
   }

   // Do more stuff...
}
Vince O'Sullivan
sumber
5

Pembungkus dasar di sekitar tujuan C yang memberi Anda fitur coba tangkap. https://github.com/williamFalcon/SwiftTryCatch

Gunakan seperti:

SwiftTryCatch.try({ () -> Void in
        //try something
     }, catch: { (error) -> Void in
        //handle error
     }, finally: { () -> Void in
        //close resources
})
William Falcon
sumber
Ide bagus. Tetapi siapa yang memutuskan untuk menggunakan ini harus mengingat bahwa objek yang dialokasikan dalam blok uji coba tidak dibatalkan alokasinya saat pengecualian dilemparkan. Ini dapat menyebabkan masalah objek zombie dan setiap penggunaan RAII terganggu (buka-otomatis, auto-sql-commit, auto-sql-rollback ...). Mungkin c ++ dapat membantu kami dengan beberapa bentuk "runAtExit"?
hariseldon78
Pembaruan: saya baru saja menemukan bahwa ada tanda di dentang untuk mengaktifkan pelepasan objek dengan pengecualian melempar: -fobjc-arc-exception. Saya harus mencoba jika masih bekerja dengan versi yang dibungkus (saya pikir seharusnya)
hariseldon78
Jika Anda menggunakan opsi ini, ketahuilah bahwa ukuran kode bertambah karena kompiler harus membuat kode semi-pengecualian-aman. Juga: Mengandalkan fitur kompiler seperti itu mungkin bukan ide terbaik. Pengecualian hanya untuk kesalahan pemrogram, jadi turing pada opsi kompilator hanya untuk menghemat sedikit memori selama pengembangan tidak sepadan. Jika Anda memiliki pengecualian dalam kode produksi Anda, Anda harus berurusan dengan hal yang menyebabkan pengecualian tersebut.
Christian Kienle
1
Mungkin ada situasi di luar kendali Anda. Misalnya, parsing json dalam format yang salah.
William Falcon
3

Ini adalah jawaban pembaruan untuk swift 2.0. Saya menantikan fitur penanganan model yang kaya fitur seperti di java. Akhirnya, mereka mengumumkan kabar baik. sini

Model penanganan kesalahan: Model penanganan kesalahan baru di Swift 2.0 akan langsung terasa alami, dengan mencoba, melempar, dan menangkap kata kunci yang familier . Terbaik dari semua, itu dirancang untuk bekerja dengan sempurna dengan SDK Apple dan NSError. Bahkan, NSError sesuai dengan ErrorType Swift. Anda pasti ingin menonton sesi WWDC di What's New in Swift untuk mendengar lebih banyak tentangnya.

misalnya:

func loadData() throws { }
func test() {
do {
    try loadData()
} catch {
    print(error)
}}
Paraneetharan Saravanaperumal
sumber
3

Sebagai Guilherme Torres Castro mengatakan, di Swift 2.0, try, catch,do dapat digunakan dalam pemrograman.

Sebagai contoh, Di CoreData mengambil metode data, bukannya dimasukkan &errorsebagai parameter ke dalammanagedContext.executeFetchRequest(fetchRequest, error: &error) , sekarang kita hanya perlu menggunakan gunakan managedContext.executeFetchRequest(fetchRequest)dan kemudian menangani kesalahan dengan try, catch( Apple Document Link )

do {
   let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) as? [NSManagedObject]
   if let results = fetchedResults{
      people = results
   }
} catch {
   print("Could not fetch")
}

Jika Anda sudah mengunduh xcode7 Beta. Cobalah untuk mencari kesalahan melempar dalam Dokumentasi dan Referensi API dan pilih hasil pertama yang ditampilkan, itu memberikan ide dasar apa yang dapat dilakukan untuk sintaks baru ini. Namun, dokumentasi lengkap belum dikirim untuk banyak API.

Teknik penanganan kesalahan yang lebih mewah dapat ditemukan di

What's New in Swift (Sesi 2015 106 28m30s)

Zingoer
sumber
1

Lib bagus dan sederhana untuk menangani pengecualian: TryCatchFinally-Swift

Seperti beberapa yang lain, ia membungkus fitur pengecualian C objektif.

Gunakan seperti ini:

try {
    println("  try")
}.catch { e in
    println("  catch")
}.finally {
    println("  finally")
}
Morten Holmgaard
sumber
Saya telah menambahkan sampel :)
Morten Holmgaard
Mungkin patut disebutkan pendapat penulis: "Peringatan: Ini adalah retasan untuk bersenang-senang dan jahat. Tahan godaan untuk menggunakannya."
jbat100
1

Dimulai dengan Swift 2, seperti yang telah disebutkan orang lain, penanganan kesalahan paling baik dilakukan melalui penggunaan do / try / catch dan enum ErrorType. Ini bekerja cukup baik untuk metode sinkron, tetapi sedikit kepintaran diperlukan untuk penanganan kesalahan yang tidak sinkron.

Artikel ini memiliki pendekatan yang bagus untuk masalah ini:

https://jeremywsherman.com/blog/2015/06/17/using-swift-throws-with-completion-callbacks/

Untuk meringkas:

// create a typealias used in completion blocks, for cleaner code
typealias LoadDataResult = () throws -> NSData

// notice the reference to the typealias in the completionHandler
func loadData(someID: String, completionHandler: LoadDataResult -> Void)
    {
    completionHandler()
    }

kemudian, panggilan ke metode di atas adalah sebagai berikut:

self.loadData("someString",
    completionHandler:     
        { result: LoadDataResult in
        do
            {
            let data = try result()
            // success - go ahead and work with the data
            }
        catch
            {
            // failure - look at the error code and handle accordingly
            }
        })

Ini tampaknya sedikit lebih bersih daripada memiliki error yang terpisah Callback handler dilewatkan ke fungsi asinkron, yang bagaimana ini akan ditangani sebelum Swift 2.

Gene Loparco
sumber
0

Apa yang saya lihat adalah bahwa karena sifat perangkat Anda tidak ingin melempar sekelompok pesan penanganan kesalahan cryptic pada pengguna. Itu sebabnya sebagian besar fungsi mengembalikan nilai opsional maka Anda hanya kode untuk mengabaikan opsional. Jika suatu fungsi kembali nihil artinya gagal Anda dapat pop pesan atau apa pun.

cheborneck
sumber
1
Mengembalikan nol tidak mengembalikan informasi tentang sifat kesalahan. Jika objek kesalahan dikembalikan ketika kesalahan terjadi maka, tergantung pada kesalahan, programmer dapat memilih untuk mengabaikannya, menanganinya, membiarkannya menggelembung atau "pop pesan atau apa pun". Pengetahuan adalah kekuatan.
Vince O'Sullivan