@@ -699,6 +699,213 @@ let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
699
699
```
700
700
-->
701
701
702
+ ## Specifying the Error Type
703
+
704
+ All of the examples above use the most common kind of error handling,
705
+ where the errors that your code throws
706
+ can be values of any type that conforms to the ` Error ` protocol.
707
+ This approach matches the reality that
708
+ you don't know ahead of time every error that could happen
709
+ while the code is running,
710
+ especially when propagating errors thrown somewhere else.
711
+ It also reflects the fact that errors can change over time.
712
+ New versions of a library ---
713
+ including libraries that your dependencies use ---
714
+ can throw new errors,
715
+ and the rich complexity of real-world user configurations
716
+ can expose failure modes that weren't visible during development or testing.
717
+ The error handling code in the examples above
718
+ always includes a default case to handle errors
719
+ that don't have a specific ` catch ` clause.
720
+
721
+ Most Swift code doesn't specify the type for the errors it throws.
722
+ However,
723
+ you might limit code to throwing errors of only one specific type
724
+ in the following special cases:
725
+
726
+ - When running code on an embedded system
727
+ that doesn't support dynamic allocation of memory.
728
+ Throwing an instance of ` any Error ` or another boxed protocol type
729
+ requires allocating memory at runtime to store the error.
730
+ In contrast,
731
+ throwing an error of a specific type
732
+ lets Swift avoid heap allocation for errors.
733
+
734
+ - When the errors are an implementation detail of some unit of code,
735
+ like a library,
736
+ and aren't part of the interface to that code.
737
+ Because the errors come from only the library,
738
+ and not from other dependencies or the library's clients,
739
+ you can make an exhaustive list of all possible failures.
740
+ And because these errors are an implementation detail of the library,
741
+ they're always handled within that library.
742
+
743
+ - In code that only propagates errors described by generic parameters,
744
+ like a function that takes a closure argument
745
+ and propagates any errors from that closure.
746
+ For a comparison between propagating a specific error type
747
+ and using ` rethrows ` ,
748
+ see < doc:Declarations:Rethrowing-Functions-and-Methods > .
749
+
750
+ For example,
751
+ consider code that summarizes ratings
752
+ and uses the following error type:
753
+
754
+ ``` swift
755
+ enum StatisticsError : Error {
756
+ case noRatings
757
+ case invalidRating (Int )
758
+ }
759
+ ```
760
+
761
+ To specify that a function throws only ` StatisticsError ` values as its errors,
762
+ you write ` throws(StatisticsError) ` instead of only ` throws `
763
+ when declaring the function.
764
+ This syntax is also called * typed throws*
765
+ because you write the error type after ` throws ` in the declaration.
766
+ For example,
767
+ the function below throws ` StatisticsError ` values as its errors.
768
+
769
+ ``` swift
770
+ func summarize (_ ratings : [Int ]) throws (StatisticsError) {
771
+ guard ! ratings.isEmpty else { throw .noRatings }
772
+
773
+ var counts = [1 : 0 , 2 : 0 , 3 : 0 ]
774
+ for rating in ratings {
775
+ guard rating > 0 && rating <= 3 else { throw .invalidRating (rating) }
776
+ counts[rating]! += 1
777
+ }
778
+
779
+ print (" *" , counts[1 ]! , " -- **" , counts[2 ]! , " -- ***" , counts[3 ]! )
780
+ }
781
+ ```
782
+
783
+ In the code above,
784
+ the ` summarize(_:) ` function summarizes a list of ratings
785
+ expressed on a scale of 1 to 3.
786
+ This function throws an instance of ` StatisticsError ` if the input isn't valid.
787
+ Both places in the code above that throw an error
788
+ omit the type of the error
789
+ because the function's error type is already defined.
790
+ You can use the short form, ` throw .noRatings ` ,
791
+ instead of writing ` throw StatisticsError.noRatings `
792
+ when throwing an error in a function like this.
793
+
794
+ When you write a specific error type at the start of the function,
795
+ Swift checks that you don't throw any other errors.
796
+ For example,
797
+ if you tried to use ` VendingMachineError ` from examples earlier in this chapter
798
+ in the ` summarize(_:) ` function above,
799
+ that code would produce an error at compile time.
800
+
801
+ You can call a function that uses typed throws
802
+ from within a regular throwing function:
803
+
804
+ ``` swift
805
+ func someThrowingFunction () -> throws {
806
+ let ratings = [1 , 2 , 3 , 2 , 2 , 1 ]
807
+ try summarize (ratings)
808
+ }
809
+ ```
810
+
811
+ The code above doesn't specify an error type for ` someThrowingFunction() ` ,
812
+ so it throws ` any Error ` .
813
+ You could also write the error type explicitly as ` throws(any Error) ` ;
814
+ the code below is equivalent to the code above:
815
+
816
+ ``` swift
817
+ func someThrowingFunction () -> throws (any Error ) {
818
+ let ratings = [1 , 2 , 3 , 2 , 2 , 1 ]
819
+ try summarize (ratings)
820
+ }
821
+ ```
822
+
823
+ In this code,
824
+ ` someThrowingFunction() ` propagates any errors that ` summarize(_:) ` throws.
825
+ The errors from ` summarize(_:) ` are always ` StatisticsError ` values,
826
+ which is also a valid error for ` someThrowingFunction() ` to throw.
827
+
828
+ Just like you can write a function that never returns
829
+ with a return type of ` Never ` ,
830
+ you can write a function that never throws with ` throws(Never) ` :
831
+
832
+ ``` swift
833
+ func nonThrowingFunction () throws (Never) {
834
+ // ...
835
+ }
836
+ ```
837
+ This function can't throw because
838
+ it's impossible to create a value of type ` Never ` to throw.
839
+
840
+ In addition to specifying a function's error type,
841
+ you can also write a specific error type for a ` do ` -` catch ` statement.
842
+ For example:
843
+
844
+ ``` swift
845
+ let ratings = []
846
+ do throws (StatisticsError) {
847
+ try summarize (ratings)
848
+ } catch {
849
+ switch error {
850
+ case .noRatings :
851
+ print (" No ratings available" )
852
+ case .invalidRating (let rating):
853
+ print (" Invalid rating: \( rating ) " )
854
+ }
855
+ }
856
+ // Prints "No ratings available"
857
+ ```
858
+
859
+ In this code,
860
+ writing ` do throws(StatisticsError) ` indicates that
861
+ the ` do ` -` catch ` statement throws ` StatisticsError ` values as its errors.
862
+ Like other ` do ` -` catch ` statements,
863
+ the ` catch ` clause can either handle every possible error
864
+ or propagate unhandled errors for some surrounding scope to handle.
865
+ This code handles all of the errors,
866
+ using a ` switch ` statement with one case for each enumeration value.
867
+ Like other ` catch ` clauses that don't have a pattern,
868
+ the clause matches any error
869
+ and binds the error to a local constant named ` error ` .
870
+ Because the ` do ` -` catch ` statement throws ` StatisticsError ` values,
871
+ ` error ` is a value of type ` StatisticsError ` .
872
+
873
+ The ` catch ` clause above uses a ` switch ` statement
874
+ to match and handle each possible error.
875
+ If you tried to add a new case to ` StatisticsError `
876
+ without updating the error-handling code,
877
+ Swift would give you an error
878
+ because the ` switch ` statement wouldn't be exhaustive anymore.
879
+ For a library that catches all of its own errors,
880
+ you could use this approach to ensure any new errors
881
+ get corresponding new code to handle them.
882
+
883
+ If a function or ` do ` block throws errors of only a single type,
884
+ Swift infers that this code is using typed throws.
885
+ Using this shorter syntax,
886
+ you could write the ` do ` -` catch ` example above as follows:
887
+
888
+ ``` swift
889
+ let ratings = []
890
+ do {
891
+ try summarize (ratings)
892
+ } catch {
893
+ switch error {
894
+ case .noRatings :
895
+ print (" No ratings available" )
896
+ case .invalidRating (let rating):
897
+ print (" Invalid rating: \( rating ) " )
898
+ }
899
+ }
900
+ // Prints "No ratings available"
901
+ ```
902
+
903
+ Even though the ` do ` -` catch ` block above
904
+ doesn't specify what type of error it throws,
905
+ Swift infers that it throws ` StatisticsError ` .
906
+ You can explicitly write ` throws(any Error) `
907
+ to avoid letting Swift infer typed throws.
908
+
702
909
## Specifying Cleanup Actions
703
910
704
911
You use a ` defer ` statement to execute a set of statements
0 commit comments