(Derived from Nick Candello's repo)
This week, we'll be going over how Swift deals with blueprinting via protocols, along with methods for error handling.
- Implement properties of a protocol
- Write a protocol from scratch
- Extend functionality of a protocol
- Implement a class which is paramaterized with a generic type
- Implement a generic struct based on a protocol
- Create a custom Error type
- Utilize do-catch for error handling
- Utilize optional conversion for error handling
Clone this repo onto your local device, either using Xcode or the command line.
Once you've cloned it, open the ProtocolsErrors
playground file if you
haven't already.
In the Protocols page of the playground, follow the instructions provided in the file.
To navigate to the Protocols page, you may need to click on the sidebar button located in the very top left of Xcode, next to the window controls.
Under the ProtocolsErrors dropdown, you should see a playground page called Protocols.
-
Take a look at
PersonalID
. Notice that the syntax is familiar to classes and structs, but with theprotocol
keyword used instead. Also notice that variable and function signatures are declared, but not defined. -
Now take a look at
DriversLicense
. It is a struct which implements thePersonalID
protocol. Similar to implementing Java interfaces, classes or structs which implement a protocol must define its functions. -
We've now defined a struct which conforms to
PersonalID
. Follow the instructions to properly initialize, manipulate, and display an instance ofDriversLicense
-
One of the primary purposes of a protocol is that it can serve as a common definition for multiple types of objects (aka polymorphism). Create a new struct called
Buzzcard
which conforms toPersonalID
. -
You may have noticed that you've had to define the
move
function individually for each struct even though the code is (or should be) identical. Implement the extension provided which changes the ID's address. -
Now, try adding a
toString()
extension from scratch. You can refer to the implementation in step 5 if needed.
- Implement properties of a protocol
- Write a protocol from scratch
- Extend functionality of a protocol
Navigate to the Generics playground page. You should see a definition for a Linked List provided as a protocol.
Your job is to implement a linked list which can handle objects of any type. It should conform to the given protocol.
-
Add an initializer (constructor) for linked list nodes. Node values should not be empty; if they are, provide a default value.
-
Implement the necessary properties and functions outlined by the LinkedList protocol in the MyLL struct. Add additional functions or properties if you would like to.
-
Test your code below by creating a linked list and testing the various functions using String as the value type. Make sure that your testing covers all of the possible return types of the functions, i.e. when
get(index: Int)
does not take in a valid index. -
Once your code is tested, copy and paste the PersonalID protocol and your Buzzcard struct into this file, and create a LinkedList of Buzzcard objects. Test your functions once again.
- Implement properties of a protocol
- Write a protocol from scratch
- Extend functionality of a protocol
- Implement a class which is paramaterized with a generic type
- Implement a generic struct based on a protocol
Navigate to the ErrorHandling playground page.
You should see a couple enums: CardValue
and CardSuit
.
You should also see a protocol Card
and a dictionary cardData
.
Our goal will be to parse the dictionary of card data, print any errors, and return an array of Card objects.
-
Take a look at the Card protocol. Notice that the init function can throw but we haven't defined an error type.
Declare a custom error type called
CardError
which deals with four possible issues that can arise when parsing a card dictionary:- Missing suit
- Missing value
- Invalid suit
- Invalid value
-
Once we've defined errors thrown by Card, let's actually implement the card protocol.
Define a struct named
StandardCard
which implementsCard
. Ensure that the init function can handle all four possible errors and throw them properly.Note that converting strings to CardValue and CardSuit can be done using the static
parse()
function defined in both enums. -
Now, let's write a function that checks if the card data contains an invalid card. This time, attempt to instantiate each card using optional conversion (i.e.
try?
). Return a boolean indicating whether all cards were instantiated successfully or not.Run the whole playground. You should get a message saying that an invalid card was found.
-
Now we'll implement a function which converts raw card data into an array of Card items. Using a do-catch block, try to parse each card and print an error specifically for the type of error thrown if it fails.
If successful, add the card to the result array.
Then, try running the whole playground. You should see the error messages that you wrote, along with an array of objects. However, this array isn't particularly human-readable.
-
Make an extension to
StandardCard
which conforms to CustomStringConvertible.A requirement of this protocol is that you provide a variable called
description
. Make this a computed variable which returns the value and suit of the card in the format[value] of [suit]
(e.g.eight of hearts
)It may be helpful to refer to the Swift docs for CustomStringConvertible.
-
Run the playground again. You should now see the error messages as before, but now the printed array should be a human-readable list!
- Implement properties of a protocol
- Write a protocol from scratch
- Extend functionality of a protocol
- Implement a class which is paramaterized with a generic type
- Implement a generic struct based on a protocol
- Create a custom Error type
- Utilize do-catch for error handling
- Utilize optional conversion for error handling