Hızlı Dilde Hata İşleme


190

Swift hakkında çok fazla şey okumadım ama fark ettiğim bir şey de istisna yok. Peki Swift'te hata işleme nasıl yapıyorlar? Hata işleme ile ilgili bir şey bulan var mı?


1
Sadece Obj-C gibi hata iletileri Bulunan: o
Arbitur

13
@Arbitur iyi eski segfault yolu?
peko

Swift'te bir NSTimer oluşturdum ve işlevi yanlış yazdığımda çöktü ve bana yöntemi bulamadığını söyleyen bir hata verdi :)
Arbitur

3
Bu makaledeki talimatları uygulayarak Swift için deneme yakalama desteği ekleyebilirsiniz: medium.com/@_willfalcon/adding-try-catch-to-swift-71ab27bcb5b8
William Falcon

@peko Swift'de segfaultla nasıl başa çıkıyorsunuz? Şu andan itibaren mümkün olduğunu sanmıyorum, bu da ne yazık ki bazı hataları düzeltilemez hale getiriyor
Orlin Georgiev

Yanıtlar:


148

Swift 2 ve 3

Swift 2'de işler biraz değişti, çünkü yeni bir hata işleme mekanizması var, bu da istisnalara biraz daha benzer, ancak ayrıntı bakımından farklı.

1. Hata olasılığını gösteren

İşlev / yöntem bir hata atabileceğini belirtmek istiyorsa, bunun throwsgibi bir anahtar kelime içermelidir

func summonDefaultDragon() throws -> Dragon

Not: İşlevin gerçekten atabileceği hata türü için herhangi bir spesifikasyon yoktur. Bu bildirim basitçe işlevin ErrorType uygulayan herhangi bir türden bir örnek atabileceğini veya hiç atmayacağını belirtir.

2. Hata atabilecek işlev çağırma

İşlevi çağırmak için try anahtar sözcüğünü kullanmanız gerekir, bunun gibi

try summonDefaultDragon()

bu çizgi normalde böyle do-catch bloğu olmalıdır

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
}

Not: catch cümlesi, Swift desen eşleşmesinin tüm güçlü özelliklerini kullanın, böylece burada çok esneksiniz.

throwsAnahtar kelime ile işaretlenmiş bir işlevden bir atma işlevi çağırıyorsanız, hatayı yaymaya karar verebilirsiniz :

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

Alternatif olarak, fırlatma fonksiyonunu kullanarak şunları çağırabilirsiniz try?:

let dragonOrNil = try? summonDefaultDragon()

Bu şekilde, herhangi bir hata oluşursa dönüş değerini veya nil değerini alırsınız. Bu yolla hata nesnesi alamazsınız.

Bu, aşağıdaki try?gibi yararlı ifadelerle de birleştirebileceğiniz anlamına gelir :

if let dragon = try? summonDefaultDragon()

veya

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

Son olarak, hatanın gerçekten gerçekleşmeyeceğini bildiğinize karar verebilirsiniz (örneğin, önceden kontrol ettiğiniz için önkoşullardır) ve try!anahtar kelime kullanın :

let dragon = try! summonDefaultDragon()

İşlev aslında bir hata atarsa, uygulamanızda bir çalışma zamanı hatası alırsınız ve uygulama sona erer.

3. Bir hata atma

Bir hata atmak için böyle bir anahtar kelime kullanın

throw DragonError.dragonIsMissing

ErrorTypeProtokole uygun her şeyi atabilirsiniz . Yeni başlayanlar NSErroriçin bu protokole uygundur, ancak muhtemelen ErrorTypebirden fazla ilgili hatayı, potansiyel olarak bunun gibi ek veri parçalarıyla gruplandırmanıza olanak tanıyan enum tabanlı ile gitmek istersiniz.

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

Yeni Swift 2 ve 3 hata mekanizması ile Java / C # / C ++ stili istisnalar arasındaki temel farklar şunlardır:

  • Sözdizimi biraz farklıdır: do-catch+ try+ deferve geleneksel try-catch-finallysözdizimine karşı.
  • Kural dışı durum işleme, kural dışı durum yolunda genellikle başarı yolundan çok daha yüksek yürütme süresi gerektirir. Başarı yolu ve hata yolunun maliyeti yaklaşık olarak aynı olan Swift 2.0 hataları için durum böyle değildir.
  • İstisnalar herhangi bir yerden atılabilirken, tüm hata atma kodlarının bildirilmesi gerekir. Tüm hatalar Java isimlendirmesinde "kontrol edilen istisnalar" dır. Bununla birlikte, Java'nın aksine, potansiyel olarak atılan hataları belirtmezsiniz.
  • Hızlı istisnalar ObjC istisnalarıyla uyumlu değildir. Sizin do-catchEğer objc kullanması gerektiğini için blok, tersi herhangi NSException, ve yardımcısı yakalamak olmaz.
  • Swift durumlar Kakao ile uyumlu olan NSErrormetot, ya geri kurallarına false(için Boolişlevler dönen) ya da nil(için AnyObjectişlevler dönen) ve pasNSErrorPointer hata ayrıntıları ile.

Hata işlemeyi kolaylaştırmak için ekstra bir syntatic-şeker olarak, iki kavram daha var

  • deferJava / C # / etc'deki bloklarla aynı etkiyi elde etmenizi sağlayan ertelenmiş eylemler ( anahtar kelime kullanarak )
  • guard deyimi ( guardanahtar kelime kullanarak ) normal hata denetimi / sinyal kodundan daha az / if kodu yazmanıza izin verir.

Hızlı 1

Çalışma zamanı hataları:

Leandros'un çalışma zamanı hatalarını (ağ bağlantısı sorunları, veri ayrıştırma, dosya açma vb. Gibi) NSErrorele almasını önerdiği gibi, Foundation, AppKit, UIKit vb. Hatalarını bu şekilde bildirdiği için ObjC'de kullandığınız gibi kullanmalısınız . Yani dil dilinden çok çerçeve şey.

Kullanılan diğer bir sık ​​desen AFNetworking gibi ayırıcı başarı / başarısızlık bloklarıdır:

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")
    })

Yine de hata bloğu, sık sık alınan NSErrorve hatayı açıklayan örneği.

Programcı hataları:

Programcı hataları için (dizi elemanının sınır dışı erişimi, bir işlev çağrısına geçirilen geçersiz argümanlar vb.) ObjC'de istisnalar kullandınız. Swift dil istisnalar için herhangi bir dil desteğine sahip görünmüyor (gibi throw, catchvb anahtar kelime). Bununla birlikte, belgelerin önerdiği gibi ObjC ile aynı çalışma zamanında çalışmaktadır ve bu nedenle hala şu şekilde fırlatabilirsiniz NSExceptions:

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

ObjC kodunda istisnaları yakalamayı tercih etmenize rağmen, bunları sadece Swift'te yakalayamazsınız.

Soru, programcı hataları için istisnalar atmanız veya Apple'ın dil kılavuzunda önerdiği gibi iddiaları kullanmanız gerekip gerekmediğidir.


20
Cocoa API'lerini (NSFileHandle) kullanarak "ağ bağlantısı sorunları" ve "dosyaları açma" yakalanması gereken istisnalar atabilir. Swift'te istisnalar olmadan, programınızın bu bölümünü Objective-C'de uygulamanız veya tüm çalışmalarınızı BSD C API'lerini (her ikisi de zayıf çözümlerdir) kullanarak yapmanız gerekir. Daha fazla bilgi için NSFileHandle.writeData belgelerine bakın ... developer.apple.com/library/ios/documentation/Cocoa/Reference/… :
Matt Gallagher

5
Yine, bir istisna işleme tüm doğal sorunları ile iki aşamalı nesne yapımı anlamına gelir. Bkz. Stroustrup.com/except.pdf .
Phil

2
fatalError(...)oyuk ile aynıdır.
holex

8
Swift'i sevdiğim kadarıyla, bunun felaket bir seçim olduğunu düşünüyorum ve bazı sonuçların tadını
Rob

2
Evet, kontrol edilen istisnalar artık çok az kullanılmaktadır, çünkü programcıyı istisnaları yakalamaya zorlamanın, kirlilik kodundan tek sorumluluk ilkesi kırma yollarında kurtarma umudu az olduğu bulunmuştur. Etki alanı düzeyinde bir sınıf, altyapı katmanı istisnalarıyla uğraşmak istemez. Dolayısıyla, kontrol edilmeyen istisnalar tercih edilir ve ilgili taraf uygunsa onları yakalayabilir. . İşaretli = kesinlikle kurtarılabilir. İşaretlenmemiş = kurtarılamaz / potansiyel olarak kurtarılamaz.
Jasper Blues

69

9 Haziran 2015 Güncellemesi - Çok önemli

Swift 2.0 ile geliyor try, throwve catchanahtar kelimeler ve en heyecan verici olduğunu:

Swift, hata üreten Objective-C yöntemlerini Swift'in yerel hata işleme işlevine göre hata atan yöntemlere otomatik olarak çevirir.

Not: Temsilci yöntemler veya bir NSError nesne bağımsız değişkeniyle tamamlama işleyicisi alan yöntemler gibi hataları tüketen yöntemler, Swift tarafından içe aktarıldığında atanan yöntemler haline gelmez.

Alıntı: Apple Inc. “Swift'i Kakao ve Objective-C (Swift 2 Ön Yayın) ile kullanma.” iBooks.

Örnek: (kitaptan)

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);
}

Hızlı eşdeğeri:

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)")
}

Hata Atma:

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

Arayana otomatik olarak yayılacak:

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

Apple kitaplarından, Swift Programlama Dili, hataların enum kullanılarak ele alınması gerektiği anlaşılıyor.

İşte kitaptan bir örnek.

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)"
}

Gönderen: Apple Inc. “Hızlı Programlama Dili.” iBooks. https://itun.es/br/jEUH0.l

Güncelleme

Apple haber kitaplarından "Swift'i Kakao ve Objective-C ile Kullanma". Hızlı diller kullanılarak çalışma zamanı istisnaları oluşmaz, bu yüzden deneme yakalamanız yoktur. Bunun yerine İsteğe Bağlı Zincirleme kullanırsınız .

İşte kitaptan bir streç:

Örneğin, aşağıdaki kod listesinde, NSDate nesnesinde length özelliği ve characterAtIndex: yöntemi bulunmadığından, birinci ve ikinci satırlar yürütülmez. MyLength sabiti isteğe bağlı bir Int olarak çıkarılır ve nil olarak ayarlanır. Üçüncü satırda gösterildiği gibi, nesnenin yanıt vermeyebileceği bir yöntemin sonucunu koşullu olarak açmak için bir if – let ifadesi de kullanabilirsiniz.

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

Alıntı: Apple Inc. “Swift'i Kakao ve Objektif-C ile Kullanma” iBooks. https://itun.es/br/1u3-0.l


Kitaplar ayrıca Objective-C'den (NSError Nesnesi) gelen kakao hata modelini kullanmanızı teşvik ediyor

Swift'teki hata bildirimi, Objective-C ile aynı modeli izler ve ayrıca isteğe bağlı dönüş değerleri sunmanın avantajını da içerir. En basit durumda, başarılı olup olmadığını belirtmek için işlevden bir Bool değeri döndürürsünüz. Hatanın nedenini bildirmeniz gerektiğinde, işleve NSErrorPointer türünde bir NSError out parametresi ekleyebilirsiniz. Bu tür, ek bellek güvenliği ve isteğe bağlı yazımla birlikte Objective-C'nin NSError ** ürününe kabaca eşdeğerdir. Aşağıdaki kod listesinde gösterildiği gibi, NSErrorPointer nesnesi olarak isteğe bağlı bir NSError türüne başvuru iletmek için önek ve işlecini kullanabilirsiniz.

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)")
    }
}

Alıntı: Apple Inc. “Swift'i Kakao ve Objektif-C ile Kullanma” iBooks. https://itun.es/br/1u3-0.l


Son ifade için: do {try myString.writeToFile (yol, atomik: true, kodlama: NSUTF8StringEncoding)} şunu yakala: NSError olarak {print (error)}
Jacky

1
@Jacky Evet, bu cevap swift 2.0'ın yayınlanmasından önce yazılmasına rağmen swift 2.0 için geçerlidir, cevabı swift 2.0'daki yeni yol tanıma hatalarını göstermek için güncelledim. Referans için bu şekilde izin vermeyi düşünüyordum, ancak tüm cevabı sadece hızlı 2.0 kullanmak için güncellemeyi düşüneceğim
Guilherme Torres Castro

12

Swift'te Objective-C'nin yaklaşımına benzer bir İstisna yoktur.

Geliştirme sırasında, assertüretime gitmeden önce ortaya çıkabilecek ve düzeltilmesi gereken hataları yakalamak için kullanabilirsiniz .

Klasik NSErroryaklaşım değişmez, bir NSErrorPointernüfus gönderirsiniz .

Kısa örnek:

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)")
}

6
Bu iki soruyu doğurur: Swift'den çağırdığımız ObjC kodu gerçekten bir istisna atarsa ​​ve NSError'un ObjC'deki gibi evrensel hata nesnemiz olup olmadığı nedir?
MDJ

1
Swift ile başlatıcıların başarısız olmadığı veya başarısız olamayacağı bir hayat gerçeği midir?
Phil

11
İstisna yönetimi oldukça kirli görünüyor
Tash Pemhiwa

27
Evet, sadece çökebileceğinde kim istisnalara ihtiyaç duyar? Veya beyan ettiğiniz tüm işlevlerde bir NSError ** 'ı argüman olarak mı koyuyorsunuz? böylece her ay ilk ay f();g();olur f(&err);if(err) return;g(&err);if(err) return;, o zaman olurf(nil);g(nil);hopeToGetHereAlive();
hariseldon78

2
Bu cevap hem eskimiş (Swift artık istisnaları destekliyor) hem de yanlış (Objective-C istisnaları destekliyor.
Rog

11

Önerilen 'Swift Way':

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
}

Ancak takip etmeyi daha kolay bulduğum için denemeyi / yakalamayı tercih ederim çünkü hata işlemeyi sonunda ayrı bir bloğa taşır, bu düzenlemeye bazen "Altın Yol" denir. Şanslı bunu kapanışlarla yapabilirsiniz:

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

Ayrıca bir yeniden deneme tesisi eklemek kolaydır:

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
}

TryBool için liste:

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)
    }
}

Bool değeri yerine İsteğe bağlı bir döndürülen değeri test etmek için benzer bir sınıf yazabilirsiniz:

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)
    }
}

TryOptional sürümü, sonraki programlamayı kolaylaştıran İsteğe Bağlı olmayan bir dönüş türünü zorunlu kılar, örneğin 'Hızlı Yol:

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

TryOptional'ı kullanma:

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
}

Otomatik açmayı not edin.


7

Düzenle: Bu cevap işe yarıyor olsa da, Swift-dönüştürülmüş Objective-C biraz daha fazla. Swift 2.0'daki değişikliklerle geçersiz hale getirildi. Guilherme Torres Castro'nun yukarıdaki cevabı, Swift'teki hataları ele almanın tercih edilen yoluna çok iyi bir giriş. Vos

Anlamak biraz zaman aldı ama sanırım bunu batırdım. Gerçi çirkin gözüküyor. Objective-C versiyonu üzerinde ince bir ciltten başka bir şey yoktur.

NSError parametresiyle bir işlev çağrılıyor ...

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
}`

Bir hata parametresi alan işlev yazılıyor ...

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...
}


5

Deneme yakalama özelliğini veren objektif C etrafındaki temel sarıcı. https://github.com/williamFalcon/SwiftTryCatch

Gibi kullanın:

SwiftTryCatch.try({ () -> Void in
        //try something
     }, catch: { (error) -> Void in
        //handle error
     }, finally: { () -> Void in
        //close resources
})

İyi bir fikir. Ancak bunu kullanmaya karar verenler, bir istisna atıldığında try bloğunda ayrılan nesnelerin yer değiştirmediğini akılda tutmalıdır. Bu zombi nesnelerinin sorunlarına neden olabilir ve RAII'nin her kullanımından ödün verilir (otomatik kilit açma, otomatik sql-kesinliği, otomatik sql geri alma ...). Belki c ++ "runAtExit" bir tür bize yardımcı olabilir?
hariseldon78

Güncelleme: Ben sadece istisna atma nesnelerin serbest bırakılmasını sağlamak için clang bir bayrak olduğunu buldum: -fobjc-arc-istisnalar. Hala sarılmış sürümü ile çalışırsa denemeliyim (sanırım gerekir)
hariseldon78

Bu seçeneği kullanırsanız, derleyicinin yarı istisna güvenli kod üretmesi gerektiğinden kod boyutunun arttığını unutmayın. Ayrıca: Böyle bir derleyici özelliğine güvenmek en iyi fikir olmayabilir. İstisnalar sadece programcı hataları içindir, bu nedenle geliştirme sırasında sadece biraz bellek tasarrufu yapmak için bu derleyici seçeneğini açmak buna değmez. Üretim kodunuzda istisnalar varsa, öncelikle bu istisnalara neden olan şeyle ilgilenmelisiniz.
Christian Kienle

1
Kontrolünüz dışında durumlar olabilir. Örneğin, json'u yanlış biçimde ayrıştırma.
William Falcon

3

Bu, swift 2.0 için bir güncelleme cevabıdır. Java gibi özellik zengin Hata işleme modeli bekliyorum. Sonunda iyi haberi duyurdular. buraya

Hata işleme modeli: Swift 2.0'daki yeni hata işleme modeli, tanıdık deneme, atma ve yakalama anahtar kelimeleriyle anında doğal bir hal alacaktır . Hepsinden iyisi, Apple SDK'ları ve NSError ile mükemmel çalışacak şekilde tasarlanmıştır. Aslında, NSError bir Swift'in ErrorType'ına uygundur. Bu konuda daha fazla şey duymak için Swift'teki Yenilikler hakkındaki WWDC oturumunu kesinlikle izlemek isteyeceksiniz.

Örneğin :

func loadData() throws { }
func test() {
do {
    try loadData()
} catch {
    print(error)
}}

3

Guilherme Torres Castro söylediği gibi, Swift 2.0, try, catch,do programlamada kullanılabilir.

Örneğin, CoreData getirme veri yönteminde, &erroriçine bir parametre olarak koymak yerine managedContext.executeFetchRequest(fetchRequest, error: &error), şimdi sadece kullanımı kullanmalı managedContext.executeFetchRequest(fetchRequest)ve ardından 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")
}

Xcode7 Beta sürümünü zaten indirdiyseniz. Aramayı deneyin hatalarına yol açan yılında Dokümantasyon ve API Başvurusu ve birinci gösteren sonucunu seçmek, bu yeni sözdizimi için neler yapılabileceğini temel bir fikir verir. Ancak, henüz birçok API için tam dokümantasyon gönderilmemiştir.

Daha süslü Hata İşleme teknikleri şurada bulunabilir:

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



1

İstisnalarla başa çıkmak için hoş ve basit bir lib: TryCatchFinally-Swift

Diğer birkaç kişi gibi, nesnel C istisna özelliklerinin etrafını sarar.

Şöyle kullanın:

try {
    println("  try")
}.catch { e in
    println("  catch")
}.finally {
    println("  finally")
}

Bir örnek ekledim :)
Morten Holmgaard

Muhtemelen yazarların görüşlerinden bahsetmeye değer: "Uyarı: Bu eğlence ve kötülük için bir hack. Kullanmak için günaha karşı koy."
jbat100

1

Swift 2'den başlayarak, diğerlerinin de belirttiği gibi, hata işleme en iyi do / try / catch ve ErrorType enum'ları kullanılarak gerçekleştirilir. Bu, senkronize yöntemler için oldukça iyi çalışır, ancak eşzamansız hata işleme için biraz akıllılık gerekir.

Bu makalede bu soruna büyük bir yaklaşım vardır:

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

Özetlemek:

// 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()
    }

daha sonra, yukarıdaki yönteme çağrı aşağıdaki gibi olacaktır:

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
            }
        })

Bu, ayrı bir hataya sahip olmaktan biraz daha temiz görünüyor.Andler geri çağrışım, eşzamansız işleve iletildi, bu da Swift 2'den önce ele alınacaktı.


0

Gördüğüm, cihazın doğası gereği, kullanıcıya bir grup şifreli hata işleme mesajı atmak istemediğinizdir. Bu yüzden çoğu işlev isteğe bağlı değerleri döndürür, sonra isteğe bağlı olarak yoksaymak için kodlarsınız. Eğer bir işlev başarısız olduğu anlamına gelmezse bir mesaj ya da her neyse başlatabilirsiniz.


1
Nil döndürmek, hatanın niteliği hakkında hiçbir bilgi döndürmez. Bir hata oluştuğunda bir hata nesnesi döndürülürse, hataya bağlı olarak, programcı bunu yok saymayı, işlemeyi, kabarmasına izin vermeyi veya "bir mesaj ya da her neyse" bırakmayı seçebilir. Bilgi Güçtür.
Vince O'Sullivan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.