2015-06-09 8 views
13

do-catch deneyin: Her iki pathForResource ve contentsOfFile atabilir, çünküSwift 2 ile izin verirsen ben bu var Swift 1.2 olarak

if let filePath = NSBundle.mainBundle().pathForResource("some", ofType: "txt"), 
     data = String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding) { 
    for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) { 
     // Do something 
    }  
} else { 
    println("some.txt is missing") 
} 

Swift 2'de, artık bunu yapabilirsiniz, hem de geri dönen opsiyoneller. Bunu düzeltmek, ancak şimdi oldukça ayrıntılı görünüyor:

do { 
    if let filePath = try NSBundle.... { 
     do { 
      if let data = try String.... { 
       for line in data..... { 
        // Do something 
       } 
      } else { 
       print("Nil data") 
      } 
     } catch { 
      print("contentsOfFile threw") 
     } 
    } else { 
     print("Nil pathForResource") 
    } 
} catch { 
    print("pathForResource threw") 
}  

Ben bir şey kaçırmış bekliyoruz - takdir herhangi bir yardım.

+1

sadece anahtar notu gördü. "Yap" bloğunda birden çok "try" ifadesine sahip olabileceğinizi düşündüm. Bu mümkün değil mi? – dreamlab

+0

Henüz bir not görmedim ama Swift'in özellik seti neredeyse çok hızlı bir şekilde genişliyor gibi görünüyor. – sbooth

+0

"try" işlevini her kullanışınızda kullanmanız gerekmez. Aslında, çoğu zaman muhtemelen istisnaları yakalamamanız gerekir, bunun yerine sadece yukarı doğru yayılmasına izin vermelisiniz. Bkz. Http://exceptionsafecode.com/ (C++ hakkında konuşur, ancak Swift'in istisna modeline baktıktan sonra prensiplerin Swift için de geçerli olduğunu düşünüyorum.) – bames53

cevap

13

if-let yerine guard sözdizimini kullanın. Burada

bir örnek aşağıda verilmiştir:

do { 

    guard let filePath = try NSBundle .... else { 
     // if there is exception or there is no value 
     throw SomeError 
    } 
    guard let data = try String .... else { 
    } 

} catch { 

} 

-izin halinde ve koruma kullanıcıya değer alanı arasındaki fark. If-let filePath değerini kullanırsanız, yalnızca if-let bloğu içinde kullanılabilir. Eğer bekçi FilePath kullanırsanız değeri, İşte

hızlı kitabın

bir if deyimi gibi bir kılavuz açıklamada, ilgili bölümdür. gardiyanın denir kapsamına kullanılabilir Boole üzerinde bağlı ifadeleri çalıştırır bir ifadenin değeri. 'a bir güvenlik bildirimi kullandığınızda, koruma bildiriminin yürütülmesinden sonra kod için bir koşulun doğru olması gerekir. If ifadesinden farklı olarak, bir guard bildiriminin her zaman başka bir yanı vardır (koşulun true olması durumunda else'ın yan tümcesi yürütülür). (pathForResource() bir noktada bir hata atma için isteğe bağlı bir değer döndürmesini değişebilir rağmen) yukarıda yalnızca dize başlatıcısı söyleyebilirim civarında

+0

Henüz denemedim, ancak bu mantıklı. Dokümanlarda, aynı dolandırıcılıkta birden fazla 'denemenin iyi olduğunu söyleyen hiçbir şey göremedim, ama bunu yapacak! Teşekkürler! – Grimxn

8

, aslında bir hata atar.

if let filePath = NSBundle.mainBundle().pathForResource("some", ofType: "txt") { 
    do { 
     let data = try String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding) 
     for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) { 
       // Do something 
     } 
    } catch { 
     print("Couldn't load the file somehow") 
    } 
} else { 
    print("some.txt is missing") 
} 

Sizin dize artık isteğe bağlıdır, bu yüzden orada bir if let için gerek yoktur: Bu nedenle, aşağıda daha önce ne yaptığını çoğaltmak gerekir. pathForResource() bir hata atma için isteğe bağlı dönen değiştirildi eğer basitçe,

guard let filePath = NSBundle.mainBundle().pathForResource("some", ofType: "txt") else { 
    print("some.txt is missing") 
} 
do { 
    let data = try String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding) 
    for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) { 
     // Do something 
    } 
} catch { 
    print("Couldn't load the file somehow") 
} 

Şimdi edebilirsiniz: mustafa işaret ettiği gibi

, bir guard açıklamada başarı durumunda girinti düzeyini kaldırmak için kullanılabilir bu dizideki ifadeleri deneyin kullanın:

do { 
    let filePath = try NSBundle.mainBundle().pathForResource("some", ofType: "txt") 
    let data = try String(contentsOfFile: filePath, encoding: NSUTF8StringEncoding) 
    for line in data.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) { 
     // Do something 
    } 
} catch { 
    print("some.txt is missing") 
} 

ilk deyimi bir hata geçmiş şey yürütülmesini engelleyen, bu noktada tekmeler atmaya. Tek bir yakalama ifadesi, bir dizi arızalanabilir işlemden bir şey almak için yeterlidir; bu da onları zincirlemeyi kolaylaştırır.

+0

Son örnekte, hata çubuğunu daha doğru bir şekilde tanımlamak için catch cümlesi nasıl güncelleştirilir, çünkü artık "some.txt eksik" diyemeyiz (belki de 'contentOfFile: encoding:'). Yoksa bazı genel "Bir şeyler ters gitti" mesajıyla sınırlı mıyız? –

+1

@BenPackard - Hata atma çizgilerinin her ikisi de bir NSError'ı geri yüklediğinden, catch ifadesiyle birlikte gelen "error" parametresi bir NSError'a güvenli bir şekilde dökülebilir ve incelenebilir. Kullanıcıya doğrudan NSError'ı kullanarak (muhtemelen en açıklayıcı değil) bir hata gösterebilir veya hata kodunu ve etki alanını bunun dışına çekebilir ve geri döndüğünüze dair hataya dayanarak kendi hata raporunuzu oluşturabilirsiniz. Tüm hata durumlarını, hata yapılabilen işlemlerden biriyle yapabilirsiniz. –

+0

Görüyorum - ve muhtemelen bir NSErrorType yerine bir NSErrorType döndüren başka bir atma işlevi eklenmişse, başka bir catch ifadesinde (veya her bir tipte bir tane) ele alınabilir. Teşekkürler. –