Challenge A: Building a collection
Consider the pet and keeper example from earlier in the chapter:
class Cat {
var name: String
init(name: String) { self.name = name
}
}
class Dog {
var name: String
init(name: String) { self.name = name
}
}
class Keeper<Animal> { var name: String
var morningCare: Animal var afternoonCare: Animal
init(name: String, morningCare: Animal, afternoonCare: Animal) { self.name = name
self.morningCare = morningCare self.afternoonCare = afternoonCare
}
}
Imagine that instead of looking after only two animals, every keeper looks after a changing number of animals throughout the day. It could be one, two, ten animals per keeper instead of just morning and afternoon ones.
You’d have to do things like the following:
let christine = Keeper<Cat>(name: "Christine")
christine.lookAfter(someCat) christine.lookAfter(anotherCat)
You’d want to be able to access the count of all of animals for a keeper like christine.countAnimals and to access the 51st animal via a zero-based index like christine.animalAtIndex(50).
Of course, you’re describing your old friend the array type, Array<Element>!
Your challenge is to update the Keeper type to have this kind of interface. You’ll probably want to include a private array inside Keeper and then provide methods and properties on Keeper to allow outside access to the array.
You’ve made it to the final section of this book! In this section, you’ll delve into some important but more advanced topics to round out your Swift apprenticeship:
- Chapter 19, Access Control and Code Organization: Swift gives you powerful tools for hiding complexity and organizing your code into easier to digest units. This chapter details how to do that.
- Chapter 20, Custom Operators and Subscripts: You’ll learn how you can define your own operators and subscripts to make your types feel even more like built-in language constructs.
- Chapter 21, Pattern Matching: With pattern matching you can accomplish more — with less typing. You’ll master all of its many forms in this chapter.
- Chapter 22, Error Handling: In the real world, some errors cannot be avoided. Handling them gracefully is what sets apart mediocre code from great code.
- Chapter 23, Async Closures and Memory Management: This chapter digs into the details of Swift memory management examining the relation between objects. It shows you how you avoid common leaks.
- Chapter 24, Value Types and Reference Types: Value semantics have a clear advantage over reference semantics in terms of the local reasoning but can lead to inefficiency for large objects. This chapter shows you how to get the best of both worlds.
- Chapter 25, Protocol-Oriented Programming: From the standard library to user authored generics, Swift is a protocol-based language. In this chapter you’ll see how to get all of the benefits associated with object-oriented programming while being able to avoid most of the difficulties.
Swift types can be declared with properties, methods, initializers, and even other nested types. These elements can be thought of as the interface to your code.
As code grows in complexity, controlling this interface becomes an important part of software design. You may wish to create methods that serve as “helpers” to your code, or properties that are designed to keep track of internal states that you don’t want as part of your code’s interface.
Swift solves these problems with a feature area known as access control, which allows you to control the viewable interface of the code you write. Access control lets you, a library author, hide implementation complexity from users. This hidden internal state is sometimes referred to as the invariant which your public interface should always maintain. Preventing direct access to the internal state of a model and maintaining the invariant is a fundamental software design concept known as encapsulation. In this chapter, you will learn what access control is, the problems it solves, and how to apply it to your code.