Swift 2: Çağrı atabilir, ancak 'try' ile işaretlenmez ve hata giderilmez


161

Xcode 7 beta'yı yükleyip hızlı kodumu Swift 2'ye dönüştürdükten sonra, anlayamadığım kodla ilgili bir sorunum var. Swift 2'nin yeni olduğunu biliyorum, bu yüzden hiçbir şey olmadığı için araştırıyorum ve anladım, bir soru yazmalıyım.

İşte hata:

Çağrı atılabilir, ancak 'try' ile işaretlenmez ve hata giderilmez

Kod:

func deleteAccountDetail(){
        let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
        let request = NSFetchRequest()
        request.entity = entityDescription

        //The Line Below is where i expect the error
        let fetchedEntities = self.Context!.executeFetchRequest(request) as! [AccountDetail]

        for entity in fetchedEntities {
        self.Context!.deleteObject(entity)
        }

        do {
            try self.Context!.save()
        } catch _ {
        }

    }

Enstantane fotoğraf: resim açıklamasını buraya girin

Yanıtlar:


168

Hatayı aynı save()çağrınız için yaptığınız gibi yakalamanız gerekir ve burada birden fazla hatayı ele aldığınız için, trytek bir do-catch bloğunda sırayla birden fazla çağrı yapabilirsiniz:

func deleteAccountDetail() {
    let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
    let request = NSFetchRequest()
    request.entity = entityDescription

    do {
        let fetchedEntities = try self.Context!.executeFetchRequest(request) as! [AccountDetail]

        for entity in fetchedEntities {
            self.Context!.deleteObject(entity)
        }

        try self.Context!.save()
    } catch {
        print(error)
    }
}

Ya da @ bames53'ün aşağıdaki yorumlarda belirttiği gibi, hatayı atıldığı yerde yakalamak genellikle daha iyi bir uygulamadır. Yöntemi çağırmak için yöntemi throwso zaman olarak işaretleyebilirsiniz try. Örneğin:

func deleteAccountDetail() throws {
    let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
    let request = NSFetchRequest()

    request.entity = entityDescription

    let fetchedEntities = try Context.executeFetchRequest(request) as! [AccountDetail]

    for entity in fetchedEntities {
        self.Context!.deleteObject(entity)
    }

    try self.Context!.save()
}

Bu bana anlamama yardım ediyor, teşekkürler.
Farhad

5
Aslında istisnanın burada yakalanması gerekmez. tryAnahtar kelimeyi işlev çağrısına eklemek ve bu işlevi olarak bildirmek mümkündür func deleteAccountDetail() throw. Veya işlevin verilen giriş için atmayacağını garanti ettiyseniz, kullanabilirsiniz try!.
bames53

4
Bunu nitpick'e getirmiyorum, ancak istisnaların meydana geldiği çoğu yerde istisna yakalamadığı istisnai istisna tabanlı hata işleme için oldukça önemlidir. İstisnaları yakalamanın uygun olduğu üç çeşit yer vardır. Diğer tüm yerlerde, kod istisnaları açıkça işlememeli ve deinit()temizlemek (ör. RAII) deferyapmak veya bazen geçici temizlik yapmak için örtük çağrılara dayanmalıdır . Daha fazla bilgi için exceptionsafecode.com adresine bakın (C ++ hakkında konuşur, ancak temel ilkeler Swift istisnaları için de geçerlidir.)
bames53

Fakat işlevi nasıl yürütürdünüz? @ Bames53 yolu ile gidersem?
Farhad

1
@NickMoore Swift geliştiricilerinin onları çağırmak için seçtikleri, gerçekte oldukları şeyde bir fark yaratmaz. Swift'in yeni hata işleme sistemi, bu terim endüstrinin geri kalanında yaygın olarak kullanıldığı için istisnaların uygulanmasıdır.
bames53

41

throwsSwift ile bildirilen bir işlevi çağırırken , işlev çağrısı sitesine tryveya ile açıklama eklemeniz gerekir try!. Örneğin, fırlatma fonksiyonu verildiğinde:

func willOnlyThrowIfTrue(value: Bool) throws {
  if value { throw someError }
}

bu fonksiyon şöyle adlandırılabilir:

func foo(value: Bool) throws {
  try willOnlyThrowIfTrue(value)
}

Burada tryokuyucuya bu işlevin bir istisna atabileceğini ve aşağıdaki kod satırlarının yürütülemeyeceğini söyleyen çağrıyı ekleriz. Ayrıca bu işleve ek açıklama eklememiz gerekir throws, çünkü bu işlev bir istisna fırlatabilir (yani willOnlyThrowIfTrue()fırlattığında, fooistisnayı otomatik olarak yukarı doğru yeniden sarar.

Büyük olasılıkla fırlatma olarak bildirilen ancak doğru girdiyi verdiğiniz için davanıza atmayacağını bildiğiniz bir işlevi çağırmak istiyorsanız, kullanabilirsiniz try!.

func bar() {
  try! willOnlyThrowIfTrue(false)
}

Bu şekilde, kodun atılmayacağını garanti ettiğinizde, istisna yayılımını devre dışı bırakmak için ekstra kaynak kodu koymak zorunda kalmazsınız.

try!çalışma zamanında uygulanır: kullanırsanız try!ve işlev atılırsa, programınızın yürütülmesi bir çalışma zamanı hatasıyla sonlandırılır.

Çoğu istisna işleme kodu yukarıdaki gibi görünmelidir: ya istisnaları ortaya çıktıklarında yukarı doğru yayarsınız, aksi takdirde olası istisnalar hariç tutulacak koşulları ayarlarsınız. Kodunuzdaki diğer kaynakların temizlenmesi nesne imhası (örn. deinit()) Veya bazen defered kodu aracılığıyla gerçekleşmelidir .

func baz(value: Bool) throws {

  var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
  var data = NSData(contentsOfFile:filePath)

  try willOnlyThrowIfTrue(value)

  // data and filePath automatically cleaned up, even when an exception occurs.
}

Herhangi bir nedenden dolayı çalıştırılması gereken, ancak bir deinit()işlevde olmayan bir kodunuz varsa, kullanabilirsiniz defer.

func qux(value: Bool) throws {
  defer {
    print("this code runs when the function exits, even when it exits by an exception")
  }

  try willOnlyThrowIfTrue(value)
}

İstisnalarla ilgilenen kodların çoğu, arayanlara yukarı doğru yayılmasını deinit()veya yol üzerinden temizlik yapmasını sağlar defer. Çünkü çoğu kod hatalarla ne yapılacağını bilmez; neyin yanlış gittiğini biliyor, ancak hata hakkında ne yapacağını bilmek için bazı üst düzey kodların ne yapmaya çalıştığı hakkında yeterli bilgiye sahip değil. Bir iletişim kutusunun kullanıcıya sunulmasının uygun olup olmadığını veya yeniden denenmesi gerekip gerekmediğini veya başka bir şeyin uygun olup olmadığını bilmez.

Bununla birlikte, daha yüksek seviye kodu, herhangi bir hata durumunda tam olarak ne yapacağını bilmelidir. Bu nedenle istisnalar, belirli hataların başlangıçta meydana geldikleri yerden, ele alınabilecekleri yere kadar kabarmasını sağlar.

İstisnaların ele alınması catchifadeler aracılığıyla yapılır .

func quux(value: Bool) {
  do {
    try willOnlyThrowIfTrue(value)
  } catch {
    // handle error
  }
}

Her biri farklı türde bir istisna yakalayan birden çok catch deyimine sahip olabilirsiniz.

  do {
    try someFunctionThatThowsDifferentExceptions()
  } catch MyErrorType.errorA {
    // handle errorA
  } catch MyErrorType.errorB {
    // handle errorB
  } catch {
    // handle other errors
  }

İstisnalar içeren en iyi uygulamalar hakkında daha fazla bilgi için bkz. Http://exceptionsafecode.com/ . Özellikle C ++ 'ı hedefliyor, ancak Swift istisna modelini inceledikten sonra temel bilgilerin Swift için de geçerli olduğuna inanıyorum.

Swift sözdizimi ve hata işleme modeli hakkında ayrıntılar için, Swift Programlama Dili (Swift 2 Ön Yayın) kitabına bakın .


Temelde kendini yakalamak hata işleyebilir? veya giriş işlevi
Farhad

1
@BrianS Özellikle 'giriş işlevi' ile ilgili olarak tam olarak ne istediğinden emin değilim, ancak 'catch' aslında istisnalar bağlamında 'handle' ile eşanlamlıdır. Yani, bir istisnayı yakalamak ve bir istisnayı ele almak, programlama dilleri söz konusu olduğunda aynı şeydir.
bames53

Sessiz olduğum bir hata var anlamadım, lütfen bana yardım edebilir misin? Invalid conversion from throwing function of type '() throws -> _' to non-throwing function type '(NSData?, NSURLResponse?, NSError?) -> Void'
Farhad

@BrianS Bir yerlerde yanlış imzalı bir işlev kullandığınız anlaşılıyor. Bir şey NSData?, NSURLResponse?, NSError?argüman olarak alınan bir işlev verilmesini bekler , ancak ona herhangi bir argüman almayan bir işlev veriyorsunuz.
bames53

Ya da bir şey istisnalar atması bildirilmeyen bir işlevin bekler ve siz de istisnalar atan bir işlev verirsiniz.
bames53
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.