2015-06-09 14 views
13

Trong Swift 1.2 Tôi có điều này:Swift 2 nếu để cho với do-try-catch

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

Trong Swift 2, tôi có thể không còn làm được điều này, bởi vì cả hai pathForResourcecontentsOfFile có thể ném, cũng như trở về tùy chọn. Tôi có thể sửa chữa nó, nhưng nó bây giờ có vẻ đáng kể tiết lộ:

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

Tôi mong đợi tôi đã bỏ lỡ điều gì đó - bất kỳ trợ giúp được đánh giá cao.

+1

vừa xem bài phát biểu. tôi nghĩ bạn có thể có nhiều câu lệnh 'try' trong khối' do'. không phải là có thể? – dreamlab

+0

Tôi chưa thấy bài phát biểu nào nhưng có vẻ như bộ tính năng của Swift đang mở rộng gần như quá nhanh. – sbooth

+0

Bạn không cần phải có một 'catch' mỗi khi bạn sử dụng' try'. Trong thực tế, hầu hết thời gian bạn có lẽ không nên bắt ngoại lệ, và thay vào đó chỉ nên để chúng lan truyền lên trên. Xem http://exceptionsafecode.com/ (Nó nói về C++, nhưng sau khi xem xét mô hình ngoại lệ của Swift, tôi nghĩ rằng các nguyên tắc áp dụng cho Swift là tốt.) – bames53

Trả lời

13

Sử dụng cú pháp bảo vệ thay vì cho phép.

Đây là một mẫu:

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 { 

} 

Sự khác biệt giữa if-phép và bảo vệ là phạm vi giá trị nào. Nếu bạn sử dụng if-let giá trị filePath chỉ có sẵn bên trong khối if-let. Nếu bạn sử dụng bảo vệ filepath giá trị có sẵn để phạm vi được bảo vệ gọi.

Dưới đây là phần có liên quan trong cuốn sách nhanh chóng

Một tuyên bố bảo vệ, giống như một câu lệnh if, thực hiện báo cáo tùy trên Boolean giá trị của biểu thức. Bạn sử dụng tuyên bố bảo vệ cho yêu cầu điều kiện phải đúng để mã sau khi tuyên bố bảo vệ được thực thi. Không giống như câu lệnh if, lệnh bảo vệ luôn có mệnh đề khác — mã bên trong mệnh đề else2 được thực hiện nếu điều kiện không đúng.

+0

Bạn chưa thể thử nó, nhưng điều đó có ý nghĩa. Tôi không thể nhìn thấy bất cứ điều gì trong các tài liệu nói rằng nó là ok để có nhiều 'try' trong cùng một nắm bắt, nhưng điều đó sẽ làm điều đó! Cảm ơn! – Grimxn

8

gần như tôi có thể nói, chỉ Chuỗi bạn khởi tạo ở trên thực sự ném một lỗi (mặc dù pathForResource() có thể thay đổi từ trả lại một giá trị tùy chọn để ném một lỗi tại một số điểm). Do đó, dưới đây sẽ tái tạo những gì bạn đã làm trước:

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

chuỗi của bạn không còn là tùy chọn, do không có nhu cầu về một if let đó.

Như mustafa chỉ ra, một tuyên bố guard thể được sử dụng để loại bỏ một mức độ thụt đầu dòng trong trường hợp thành công:

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

Bây giờ, nếu pathForResource() thay đổi từ trả lại một tùy chọn để ném một lỗi, bạn có thể đơn giản sử dụng các câu lệnh thử này theo trình tự:

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

Câu lệnh đầu tiên để ném một lỗi sẽ bắt đầu tại điểm đó, ngăn chặn việc thực hiện bất kỳ lỗi nào trước đó. Một câu lệnh khai thác duy nhất là đủ để nhận bất cứ thứ gì từ một loạt các hoạt động có sẵn, giúp dễ dàng kết nối chúng.

+0

Trong ví dụ cuối cùng, cách cập nhật mệnh đề catch để mô tả chính xác hơn lỗi, vì chúng ta không thể nói rằng "some.txt bị thiếu" (có lẽ nó là 'contentsOfFile: encoding:' đã ném)? Hay chúng ta bị giới hạn trong một số thông điệp chung "Đã xảy ra sự cố"? –

+1

@BenPackard - Bởi vì cả hai dòng lỗi ném trở lại một NSError, tham số 'error' ngầm định đi kèm với câu lệnh catch có thể được an toàn truyền tới một NSError và được kiểm tra. Bạn có thể trình bày lỗi cho người dùng trực tiếp bằng cách sử dụng NSError đó (có lẽ không phải là mô tả nhất), hoặc bạn có thể kéo mã lỗi và miền ra khỏi nó và xây dựng báo cáo lỗi của riêng bạn dựa trên lỗi chính xác mà bạn đã nhận được. Bạn có thể xử lý tất cả các trường hợp lỗi từ một trong các hoạt động có sẵn. –

+0

Tôi thấy - và có lẽ nếu một chức năng ném khác đã được thêm vào mà trả về một số NSErrorType thay vì một NSError, có thể được xử lý trong một câu lệnh khai thác khác (hoặc một cho mỗi loại). Cảm ơn. –

Các vấn đề liên quan