Xử lí lỗi đã có 1 bước tiến dài kể từ mô hình swift 1 - được lấy cảm hứng từ Objective C. Cải tiến lớn trong swift 2 làm bạn xử lý các trạng thái và hoàn cảnh bất ngờ trong ứng dụng của bạn 1 cách minh bạch

Cũng giống như cáo ngôn ngữ lập trình phổ biến khác, các kỹ thuật xử lí lỗi được ưa chuộng trong Swift có thể khác nhau, tùy thuộc vào loại lỗi gặp phải và kiến trúc tổng thể của ứng dụng bạn làm

Hướng dẫn này sẽ đưa cho bạn 1 ví dụ với ý nghĩa ma thuật để minh họa cách tốt nhất để đối phó với các tình huống gặp lỗi. Bạn cũng có thể thấy cách nâng cấp việc xử lí lỗi trong các văn bản trước đó của Swift, cuối cùng, nhìn vào quả cầu tiên tri và nhìn vào tương lai của việc xử lí lỗi trong Swift 

Lưu ý hướng dẫn này giả định rằng bạn đã quen thuộc với cú pháp của Swift 2, đặc biệt là về enumeration và optionals. Nếu bạn cần biết các khái nhiện, hãy bắt đầu với What’s New in Swift 2  của Greg Heo.

Đã đến lúc đi vào chủ đề và khám phá những nét quyến rũ của xử lí lỗi trong Swift 2!

 

Bắt đầu

Có 2 playgrounds cho hướng dẫn này. Hãy download Avoiding Errors with nil – Starter.playground và Avoiding Errors with Custom Handling – Starter.playground playgrounds.

Mở Avoiding Errors with nil – Starter.playground bằng Xcode.

Đọc qua code bạn có thể thấy 1 số class, struct và enum – những cái nắm giữ sự kì diệu của bài hướng dẫn này

Hãy lưu ý những đoạn code dưới đây:

protocol MagicalTutorialObject {
 var avatar: String { get }
}

Giao thức này được áp dụng cho tất cả các class và struct được sử dụng trong hướng dẫn để cung cấp 1 hình ảnh đại diện của từng đối tượng sẽ được in ra ở console.

enum MagicWords: String {
 case Abracadbra = "abracadabra"
 case Alakazam = "alakazam"
 case HocusPocus = "hocus pocus"
 case PrestoChango = "presto chango"
}

Sự liệt kê này biểu thị những “từ phép thuật” cái mà có thẻ được sử dụng để tạo 1 ”Câu thần chú”.

struct Spell: MagicalTutorialObject {
 var magicWords: MagicWords = .Abracadbra
 var avatar = "*"
}

Đây là đoạn mã cơ bản cho 1 câu thần chú. Theo mặc định bạn khởi tạo   

Bây giờ bạn đang làm quen với những điều cơ bản của thế giới siêu nhiên này. Bạn dã sẵn sang tạo nên 1 vài câu thần chú.


Tại sao tôi nên quan tâm về Xử lí lỗi ?

“Xử lí lỗi là 1 nghệ thuật thiếu sự duyên dáng”( “Error handling is the art of failing gracefully.”)  –Swift Apprentice, chương 21 (Error Handling)

Xử lí lỗi tốt làm gia tăng trải nhiệm của người dùng cuối (end- user) cũng như việc bảo trì phần mềm bởi vì nó nó tạo sự dễ dàng trong việc xác minh vấn đề, nguyên nhân và mức độ nghiêm trọng.  Càng rõ ràng trong việc sử lí lỗi trong suốt code, càng dễ dàng phân tích vấn đề. Xử lí lỗi cũng cho phép hệ thống lỗi 1 cách thích hợp tránh việc gây thất vọng hay bực bội người dùng.

Nhưng lỗi không cần lúc nào cũng phải được xử lí. Khi không xử lí, tính năng ngôn ngữ cho phép bạn trách các lỗi này. Nếu bạn không thể tránh được khả năng xuất hiện lỗi, vậy thì dứt khoát xử lí nó, đó là lựa chọn tốt nhất 

Tránh các lỗi Swiff sử dụng nil

Kể từ khi swift có khả năng xử lí Optinal, bạn hoàn toàn tránh được các lỗi mà bạn mong đợi có giá trị nhưng không có giá trị nào được trả về. Là 1 lập trình viên, bạn có thể sử dụng chức năng này để cố tình trả về nil trong 1 điều kiện lỗi. Phương pháp này hoạt động tốt nhất nếu bạn không có hành động gì nếu bạn đạt đến 1 trạng thái lỗi. Ví dụ: bạn sẽ không xử lý khi gặp phải lỗi.

Hai kiểu  tránh lỗi sử dụng nil là failable initializers và guard statements.

Failable initializers

 

Failable initializers ngăn chặn việc tạo ra 1 đối tượng nếu không có đủ thông tin được cung cấp . Trước Swift (và các ngôn ngữ khác), chức năng này thường được thực hiện qua mô hình Factory Method.

Một ví dụ của mô hình này trong Swift có thể được nhìn thấy trong hàm createWithMagicWord()

static func createWithMagicWords(words: String) -> Spell? {
 if let incantation = MagicWords(rawValue: words) {
   var spell = Spell()
   spell.magicWords = incantation
   return spell
 }
 else {
   return nil
 }
}

Việc khởi tạo ở trên tạo ra 1 câu thần chú bằng cách sử dụng các từ phép thuật được cung cấp(thuộc kiểu  enum). Nếu những từ đó không phải từ phép thuật bạn trả về nil

Kiểm tra việc tạo các câu thần chú ở những dòng cuối của hướng dẫn:

Trong khi dòng đầu tiên khởi tạo thành công 1 Spell bằng cách sử dụng từ phép thuật “abracadabra”, thì “ascendio” không có hiệu ứng tương tự, nó trả về giá trị nil (Hey, phù thủy không thể lúc nào cũng giành chiến thắng)

Factory method là 1 phong cách lập trình cũ. Có nhiều cách tốt hơn để đạt được những điều tương tự trong Swift. Bạn sẽ cập nhật Spell bằng cách dùng Failable initializers thay vì sử dụng 1 Factory method    

init?(words: String) {
 if let incantation = MagicWords(rawValue: words) {
   self.magicWords = incantation
 }
 else {
   return nil
 }
}

Trong ví dụ trên bạn đã đơn giản hóa code bằng cách không tạo và trả về đối tượng Spell

Bây giờ những dòng gán giá trị “first” và “second” sẽ bị lỗi biên dịch

let first = Spell.createWithMagicWords("abracadabra")
let second = Spell.createWithMagicWords("ascendio")

Bạn cần thay đổi chúng thành: 

let first = Spell(words: "abracadabra")
let second = Spell(words: "ascendio")

Sau hành động đó, các lỗi nên được sửa và playground nên được biên dịch mà không có lỗi. Với sự thay đổi trên, code của bạn trở nên ngăn nắp, tuy nhiên bạn có thể làm tốt hơn nữa.

Guard Statements

guard là 1 cách nhanh chóng khi muốn khẳng định 1 điều gì đó là đúng, ví dụ, nếu 1 giá trị lớn hơn 0, hoặc 1 đều kiện có thể unwrapped. Bạn có thể thực thi 1 khối lệnh sau đó nếu kiểm tra lỗi.

guard được giới thiệu trong Swift 2.0 và thường được sử dụng để sử lí lỗi bubble-up thông qua việc gọi stack, nơi mà các lỗi sẽ được xử lý. Guard statements cho phép sớm thoát khỏi 1 function hoặc 1 method

Sửa code như dưới đây để sử dụng guard:

init?(words: String) {
 guard let incantation = MagicWords(rawValue: words) else {
   return nil
 }
 self.magicWords = incantation
}

 

Avoiding Errors with Custom Handling

Sau khi khởi tạo Spell và tránh 1 số lỗi bằng cách sử dụng nil, bạn đã sẵn sàng xử lí 1 số lỗi phức tạp hơn

Đây là phần tiếp theo của hướng dẫn, mở Avoiding Errors with Custom Handling – Starter.playground.

Ghi nhớ 1 số chức năng sau của code:

struct Spell: MagicalTutorialObject {
 
 var magicWords: MagicWords = .Abracadbra
 var avatar = "*"
 
 init?(words: String) {
   guard let incantation = MagicWords(rawValue: words) else {
     return nil
   }
   self.magicWords = incantation
 }
 
 init?(magicWords: MagicWords) {
   self.magicWords = magicWords
 }
}

Đây là khởi tạo Spell, cập nhật phù hợp với những gì bạn hoàn thành ở phần 1 của hướng dẫn. Và cũng chú ý sự hiện diện của MagicalTutorialObject protocol và failable initializer thứ 2, cái mà được thêm vào cho thuận tiện

protocol Familiar: MagicalTutorialObject {
 var noise: String { get }
 var name: String? { get set }
 init()
 init(name: String?)
}

Familiar protocol sẽ được áp dụng cho các đối tượng khác nhau (như dơi, cóc…)

struct Witch: MagicalBeing {
 var avatar = "*"
 var name: String?
 var familiar: Familiar?
 var spells: [Spell] = []
 var hat: Hat?
 
 init(name: String?, familiar: Familiar?) {
   self.name = name
   self.familiar = familiar
 
   if let s = Spell(magicWords: .PrestoChango) {
     self.spells = [s]
   }
 }
 
 init(name: String?, familiar: Familiar?, hat: Hat?) {
   self.init(name: name, familiar: familiar)
   self.hat = hat
 }
 
 func turnFamiliarIntoToad() -> Toad {
   if let hat = hat {
     if hat.isMagical { // When have you ever seen a Witch perform a spell without her magical hat on ? :]
       if let familiar = familiar {   // Check if witch has a familiar
         if let toad = familiar as? Toad {  // Check if familiar is already a toad - no magic required
           return toad
         } else {
           if hasSpellOfType(.PrestoChango) {
             if let name = familiar.name {
               return Toad(name: name)
             }
           }
         }
       }
     }
   }
   return Toad(name: "New Toad")  // This is an entirely new Toad.
 }
 
 func hasSpellOfType(type: MagicWords) -> Bool { // Check if witch currently has appropriate spell in their spellbook
   return spells.contains { $0.magicWords == type }
 }
}

Cuối cùng với phù thủy

  • 1 phù thủy  được khởi tạo với 1 tên và 1 familiar, hoặc với 1 tên, 1 familiar và 1 mũ)
  • 1 phù thủy biết giới hạn số phép thuật, được ghi trong spells, cái là 1 chuỗi các đối tượng Spell)
  • 1 phù thủy có thiên hướng biến“familiar” thành 1 “toad”bằng cách dùng .PrestoChango, trong turnFamiliarIntoToad().

Lưu ý, nếu có bất cứ điều gì sai trong method, 1 con cóc hoàn toàn mới sẽ được trả về. Nó nhìn giống như 1 kết quả khó hiểu (và không chính xác). Bạn sẽ làm sạch nó với tùy chỉnh xử lí lỗi tròng phần tiếp theo
 

Sắp xếp xử dụng lỗi Swift 

Không nhầm lẫn với Temple of Doom, Pyramid of Doom là 1 anti-pattern được tìm thấy trong swift và ngôn ngữ khác cái mà có thể yêu cầu nhiều mức độ báo cáo lồng nhau để kiểm soát flow (dòng chảy). Nó có thể được nhìn thấy ở hàm turnFamiliarIntoToad() trên – lưu ý nó sử dụng 6 dấu đóng ngoặc, kéo xuống theo 1 đường chéo. Đọc mã lồng nhau như thế này đòi hỏi 1 nỗ lực đáng kể

Các câu lệnh Guard, như các bạn đã thấy từ trước, sử dụng nhiều optional binding có thể hỗ trợ việc làm gọn code. Sử dụng 1 cơ chế do-catch, tuy nhiên, loại bỏ 1 vấn đề hoàn toàn bằng cách chia dòng điều khiển từ xử lí trạng thái lỗi

Cơ chế do-catch có vài từ khóa:

  • throws
  • do
  • catch
  • try
  • defer
  • ErrorTyp

Để xem cơ chế này vận hành, bạn sẽ quăng nhiều lỗi tùy chỉnh . Đầu tiên bạn cần xác định trạng thái bạn muốn xử lí bằng việc liệt kê tất cả những gì có thể sai như một enumeration.

Thêm code sau đây vào playground của bạn ở trên định nghĩa của Witch:

enum ChangoSpellError: ErrorType {
 case HatMissingOrNotMagical
 case NoFamiliar
 case FamiliarAlreadyAToad
 case SpellFailed(reason: String)
 case SpellNotKnownToWitch
}

Có 2 điều cần lưu ý về ChangoSpellError:

  • Nó phù hợp với giao thức ErrorType, một yêu cầu để xác định lỗi trong Swift
  • Trong trường hợp SpellFailed bạn có thể chỉ rõ lí do thất bại với 1 giá trị liên quan 

Ok, bạn đã sẵn sàng cho việc thực hiện 1 số phép thuật? Chỉ ra những lỗi có thể xảy ra như một kết quả của việc gọi method này:

func turnFamiliarIntoToad() throws -> Toad {

Cũng như cập nhật nó  trên giao thức MagicalBeing:

protocol MagicalBeing: MagicalTutorialObject {
 var name: String? { get set }
 var spells: [Spell] { get set }
 func turnFamiliarIntoToad() throws -> Toad
}

Bây giờ bạn đã có các trạng thái lỗi được liệt kê, bạn sẽ làm lại với turnFamiliarIntoToad() method, một điều khoản tại 1 thời điểm.

Kiểm soát lỗi “Hat”

Sử các câu lệnh sau đây để đảm bảo phù thủy đội mũ.

if let hat = hat {

Như sau : 

guard let hat = hat else {
 throw ChangoSpellError.HatMissingOrNotMagical
}

lưu ý: đừng quên bỏ dấu } ở cuối nếu không sẽ bị lỗi biên dịch 

Dòng tiếp theo chứa 1 kiểm tra Boolean

if hat.isMagical {

Bạn có thể thêm 1 câu lệnh guard riêng biệt để thực hiện việc kiểm tra này, nhưng nó sẽ dễ dàng cho nhóm kiểm tra cùng nhau trên 1 dòng. Như vậy :

guard let hat = hat where hat.isMagical else {
 throw ChangoSpellError.HatMissingOrNotMagical
}

Bây giờ xóa:

if hat.isMagical {

Kiểm soát lỗi “familiar”

Tiếp theo, thay đổi câu lệnh cái mà kiểm tra phù thủy có familiar

if let familiar = familiar {

Thành

guard let familiar = familiar else {
 throw ChangoSpellError.NoFamiliar
}

Bỏ qua mọi lỗi có thẻ xảy ra trong thời điểm này, nó sẽ biến mất với sự thay đổi tiếp

Kiểm soát lỗi “Toad”

Trong dòng tiếp theo, bạn trả về con cóc nếu phù thủy dùng turnFamiliarIntoToad() trên con vật của cô ấy

Với đoạn mã dưới đây nó sẽ trả về “toad” nếu “witch” ép kiểu về “toad”

if let toad = familiar as? Toad {
 return toad
}
if familiar is Toad {
 throw ChangoSpellError.FamiliarAlreadyAToad
}

Lưu ý, thay đổi từ “as?” thành “is”, cho phép bạn kiểm tra ngắn gọn cho phù hợp hơn với các giao thức  mà không cần phải sử dụng 1 kết quả trả về. Từ khóa “is” có thể sử dụng cho các kiểu so sánh 1 cách tổng quát hơn

Di chuyển tất cả trong else ra ngoài else,  và xóa else, nó không còn cần thiết.

Kiểm soát lỗi “Spell”

 

Cuối cùng hasSpellOfType(type:) được gọi, đảm bảo rằng Witch(phù thủy) có thần chú thích hợp trong sách thần chú của cô

Thay đổi code dưới đây:

if hasSpellOfType(.PrestoChango) {
 if let toad = f as? Toad {
   return toad
 }
}

Thành :

guard hasSpellOfType(.PrestoChango) else {
 throw ChangoSpellError.SpellNotKnownToWitch
}
 
guard let name = familiar.name else {
 let reason = "Familiar doesn’t have a name."
 throw ChangoSpellError.SpellFailed(reason: reason)
}
 
return Toad(name: name)

Và bây giờ bạn có thể loại bỏ dòng cuối cùng của code:

return Toad(name: "New Toad")

Bây giờ bạn đã có 1 method sạch sẽ và gọn gàng, sẵn sàng cho sử dụng. Tôi đã cung cấp 1 vài giải thích bổ sung vào code bên dưới, nó giải thích method đang thực hiện những gì:

func turnFamiliarIntoToad() throws -> Toad {
 
 // When have you ever seen a Witch perform a spell without her magical hat on ? :]

 guard let hat = hat where hat.isMagical else {
   throw ChangoSpellError.HatMissingOrNotMagical
 }
 
 // Check if witch has a familiar
 guard let familiar = familiar else {
   throw ChangoSpellError.NoFamiliar
 }
 
 // Check if familiar is already a toad - if so, why are you casting the spell?
 if familiar is Toad {
   throw ChangoSpellError.FamiliarAlreadyAToad
 }
 guard hasSpellOfType(.PrestoChango) else {
   throw ChangoSpellError.SpellNotKnownToWitch
 }
 
 // Check if the familiar has a name
 guard let name = familiar.name else {
   let reason = "Familiar doesn’t have a name."
   throw ChangoSpellError.SpellFailed(reason: reason)
 }
 
 // It all checks out! Return a toad with the same name as the witch's familiar
 return Toad(name: name)
}

Bạn đơn giản có thể trả về một optinal từ turnFamiliarIntoToad() để chỉ ra rằng “1 cái gì đó đã sai khi câu thần chú(spell) được thực hiện”, nhưng sử dụng các lỗi tùy chỉnh (custom error) sẽ giúp dễ dàng thể hiện trạng thái lỗi hơn và cho phép bạn có phản ứng phù hợp.

What Else Are Custom Errors Good For?

 

Bây giờ bạn có 1 method để ném các lỗi tùy chỉnh swift, bạn cần sử lí chúng. Cơ chế tiêu chuẩn để thực hiện là lệnh do-catch, nó tương tự như cơ chế try-catch trong các ngôn ngữ khác nhự java chẳng hạn

Thêm đoạn code sau xuống dưới cùng playground của bạn

func exampleOne() {
 print("") // Add an empty line in the debug area
 
 // 1
 let salem = Cat(name: "Salem Saberhagen")
 salem.speak()
 
 // 2
 let witchOne = Witch(name: "Sabrina", familiar: salem)
 do {
   // 3
   try witchOne.turnFamiliarIntoToad()
 }
 // 4
 catch let error as ChangoSpellError {
   handleSpellError(error)
 }
 // 5
 catch {
   print("Something went wrong, are you feeling OK?")
 }
}

Dưới đây là những gì chúng thực hiện:

  1. Tạo 1 familiar cho phù thủy này. Đó là 1 con mèo tên Salem
  2. Tạo 1 phù thủy tên là Sabrina
  3. Cố gắng biến con mèo thành con cóc
  4. Bắt  lỗi ChangoSpellError và xử lí lỗi 1 cách thích hợp
  5. Bắt tất cả các lỗi khác và in ra 1 thông điệp

 

Sau khi bạn thêm đoạn code ở trên có thông báo lỗi, hãy sửa nó

dleSpellError() chưa được khai báo, do đó thêm đoạn mã sau trước exampleOne()

func handleSpellError(error: ChangoSpellError) {
 let prefix = "Spell Failed."
 switch error {
   case .HatMissingOrNotMagical:
     print("\(prefix) Did you forget your hat, or does it need its batteries charged?")
 
   case .FamiliarAlreadyAToad:
     print("\(prefix) Why are you trying to change a Toad into a Toad?")
 
   default:
     print(prefix)
 }
}

Cuối cùng thêm đoạn mã sau 

exampleOne ()

Khám phá Debug console bằng cách ấn vào hình mũi tên cuối cùng bên trái của của Xcode workspace để có thể xem output của playground

Bắt lỗi

Dưới đây là 1 cuộc thảo luận ngắn gọn về mỗi tính năng của ngôn ngữ được sử dụng ở đoạn code trên

catch

Bạn có thể sử dụng mô hình phù hợp trong swift  để xử lí các lỗi cụ thể hoặc nhóm các lỗi giống nhau

Đoạn mã trên cho thấy rõ 1 số công dụng của catch :  một là bắt lỗi cụ thể changoSpellError và một các lỗi còn lại

try

Bạn sử dụng try chung với do-catch để có thể dễ dàng chỉ ra đoạn mã thể ném lỗi

Bạn có thẻ sử dụng try vài cách khác nhau, 1 trong số đó được dùng ở trên

  • try: cách sử dụng cơ bản trong 1 câu lệnh do-catch trực tiếp và rõ ràng. Nó đã được sử dụng ở trên.
  • try?: xử lí lỗi bằng cách bỏ qua nó. Nếu lỗi xảy ra, kết quả trả về sẽ là nil
  • try!: tương tự cú pháp dành cho force-unwrapping, tiền tố này sẽ tạo ra những kì vọng, trên lí thuyết, câu lệnh có thể ném lỗi, trong thực tế các lỗi sẽ không bao giờ xảy ra. try! xử dụng cho các hành động như tải 1 tập tin, tại nơi bạn chắc chắn  các file cần thiết có tồn tại. Giống như unwrap, cấu trúc này cần được sử dụng cẩn thận

Bây giờ hãy kiểm tra try? trong hành động. Cut và paste đoạn mã sau vào cuối của playground

func exampleTwo() {
 print("") // Add an empty line in the debug area
 
 let toad = Toad(name: "Mr. Toad")
 toad.speak()
 
 let hat = Hat()
 let witchTwo = Witch(name: "Elphaba", familiar: toad, hat: hat)
 
 let newToad = try? witchTwo.turnFamiliarIntoToad()
 if newToad != nil { // Same logic as: if let _ = newToad
   print("Successfully changed familiar into toad.")
 }
 else {
   print("Spell failed.")
 }
}

Lưu ý sự khác biệt với exampleOne. Toad không được tạo, vậy nên giá trị của newToad là nil

Propagating Errors

throws

Từ khóa “throws” là cần thiết trong Swift nếu 1 function hay 1 method throws 1 lỗi. Các lỗi sẽ được ném ra 1 cách tuần tự, nhưng để bong bóng lỗi quá xa nguồn được coi là 1 hành động lỗi. Ý nghĩa của propagation trong khắp codebase làm tăng khả năng lỗi sẽ thoát khỏi việc xử lí thích hợp, vì vậy throws là 1 nhiệm vụ đảm bảo propagation được ghi lại trong code và hiển nhiên là dành cho coder

rethrows

Hầu hết các ví dụ bạn đã nhìn thấy cho đến nay sử dụng throws, vậy về rethrows?

Rethrows nói với trình biên dịch rằng chức năng này chỉ throw 1 lỗi khi function parameter throw 1 lỗi. 1 ví dụ nhanh có thể tìn thấy dưới đây, (không cần thêm vào playground):

func doSomethingMagical(magicalOperation: () throws -> MagicalResult) rethrows -> MagicalResult {
  return try magicalOperation()
}

Tại đó, SomethingMagical(_:)  sẽ chỉ throw 1 lỗi nếu magicalOperation cung cấp 1 function throws. Nếu nó thành công sẽ chả về 1 MagicalResult instead

Manipulating Error Handling Behavior

defer

Mặc dù auto-propagation sẽ phục vụ bạn tốt trong hầu hết trường hợp, có những tình hướng bạn sử dụng code của bạn để ném ra các lỗi.

Câu lệnh defer là 1 cơ chế cho phép hành động “dọn dẹp” được thực hiện bất cứ khi nào phạm vi hiện tại đã bị thoát, chẳng hạn là như khi 1 function hay 1 method đã được trả về. Nó rất hữu ích cho việc quản lí các nguồn tài nguyên cần được sắp xếp gọn gàng hay các hành động không thành công, do đó nó đặc biệt hữu ích trong việc xử lí lỗi

Để thấy cách hoạt động, thêm đọn code sau vào Witch Structure:

func speak() {
  defer {
    print("*cackles*")
  }
  print("Hello my pretties.")
}

Thêm đoạn sau vào cuối playground :

func exampleThree() {
  print("") // Add an empty line in the debug area
 
  let witchThree = Witch(name: "Hermione", familiar: nil, hat: nil)
  witchThree.speak()
}

Trong debug console, bạ có thể thấy những lời nói nhảm (witch cackle) sau tất cả những thứ cô nói.Điều thú vị là. Câu lệnh defer được thực thi theo thứ tự ngược lại tại nơi nó được viết.Thêm 1câu lệnh defer :

func speak() {
  defer {
    print("*cackles*")
  }
 
  defer {
    print("*screeches*")
  }
 
  print("Hello my pretties.")
}

Câu lênh in ra có làm bạn bất ngờ? Ah, điều kì diệu của prefer

Nhiều điều thú vị hơn nữa với Errors

Việc đưa các câu lệnh vào bên trong Swift mang đến cho ngôn ngữ này sự phù hợp cới nhiều ngôn ngữ phổ biến khác và tách Swift từ NSError-based được tìm thấy trong Objective-C. Objective-C, với hầu hết các thành phần, trực tiếp dịch và phân tích tĩnh trong trình biên dịch là một điều tuyệt với bạn cần nắm bắt.

Mặc dù do-catch và các chức năng liên quan có ý nghĩa rất quan trọng trong các ngôn ngữ khác, nhưng trong swift nó được đối xử như các câu lệnh khác. Điều này đảm bảo nó hiệu quả và hiệu quả hơn

Nhưng chỉ vì bạn có thể tạo ra các tùy chỉnh lỗi và ném chúng xung quanh, không có nghĩa là bạn bạn nên làm điều đó. Bạn thực sự cần xây dựng hướng dẫn khi throw và catch lỗi cho mỗi dự án mà bạn đảm nhận. Tôi muốn đề nghị 1 số điều sau:

Đảm bảo các loại lỗi được đạt tên rõ ràng trên codebase của bạn

Sử dụng optionals tại nơi có 1 lỗi tồn tại

Sử dụng custom errors tại chỗ có nhiều hơn 1 lỗi tồn tại

Không cho phép 1 lỗi được truyền quá xa source

 

Tương lai của việc xử lí lỗi trong swift

Một vài ý tưởng cho việc xử lí lỗi đang được bàn luận trên các diễn đàn về Swift. Mọt trong những khái niệm được bàn nhiều nhất là untyped propagation.

“Chúng tôi tin rằng chúng ta có thể mở rộng mô hình hiện tại để hỗ trợ untyped propagation cho các universal errors. Làm tốt điều này, và đặc biệt là làm việc đó à không hoàn toàn hi sinh kích thức code và chất lượng, sẽ thấy tầm quan trọng của việc lập kế hoạch và sự hiểu biết sâu sắc. Vì lí do này nó được coi là nằm ngoài phạm vi của Swift 2.0”

Cho dù bạn thích ý tưởng sẽ có sự thay đổi lớn về việc xử lí lỗi trong Swift 3, hoặc hạnh phúc với những gì hiện tại, nó là 1 điều tốt đẹp nếu biết cách rõ ràng việc xử lí lỗi đang được bản luận và cải thiện ngôn ngữ phát triển

 

Đi đâu từ đây?

Bạn có thể download toàn bộ playground cho bài hướng dẫn này here

Để đọc thêm, tôi khuyên bạn nên đọc các bài sau, 1 số trong đó đã được tham chiếu trong suốt bài hướng dẫn này

·       Swift Apprentice, Chapter 21 – Error Handling

·       Failable Initializers

·       Factory Method Pattern

·       Pyramid of Doom

Nếu bạn quan tâm đến những cái có thể là bịa đặt trong Swift 3, tôi khuyên nên đọc những dề nghị mở, đọc Swift Language Proposals để biết thêm chi tiêt. Nếu bạn quan tâm , tại sao không submit của riêng bạn.

Hi vọng bây giờ bạn đã bị mê hoặc bởi việc xử lí lỗi trong Swift. Nếu bạn có bất kì câu hỏi nào hoặc ý kiến về hướng dẫn, hãy tham gia thảo luận ở dưới.

Nguồn bài viết: link

Tham gia ngay khoá học lập trình iOS, hình thức học tập rất linh hoạt cho bạn lựa chọn và sẽ có mức học phí khác nhau tuỳ theo bạn chọn học Online, Offline hoặc FlipLearning(Kết hợp giữa Online và Offline). Ngoài ra bạn có thể tham gia thực tập toàn thời gian tại Techmaster để rút ngắn thời gian học và tăng cơ hội việc làm.