Introduction to Object-Oriented Programming

Oct 17 2023 · Swift 5.9, iOS 17, Xcode 15

Lesson 04: Protocols & Interfaces

Demo

Episode complete

Play next episode

Next
Transcript

Demo

In this demo, you’ll make MuseumObject conform to Equatable and CustomStringConvertible. Then you’ll create a protocol and a subclass of MuseumObject that adopts it.

Open the playground in the starter folder or continue with your playground from the previous lesson. You won’t change any code in PublicDomainObject or MuseumObjectView, so fold their code out of the way.

Also fold MuseumObject while you try out the Swift standard library protocols Equatable and CustomStringConvertible.

Below MuseumObject, add this extension:

extension MuseumObject: Equatable {
}

Pause, and you’ll see an error message. If it doesn’t appear, run the playground.

Type 'MuseumObject' does not conform to protocol 'Equatable'
Do you want to add protocol stubs?

Click the Fix button, and Xcode gives you the method stub you need to fill in:

static func == (lhs: MuseumObject, rhs: MuseumObject) -> Bool {
  <#code#>
}

Replace the code placeholder:

lhs.objectID == rhs.objectID

objectID is a unique identifier for MuseumObject instances, so you only need to test these values are the same.

Scroll down to let object and let object_pd. At the end of the previous lesson, you created these objects with the same art object.

let object =
MuseumObject(objectID: 436535,
             title: "Wheat Field with Cypresses",
             objectURL: "https://www.metmuseum.org/art/collection/search/436535",
             creditLine: "Purchase, The Annenberg Foundation Gift, 1993",
             isPublicDomain: true)
             
let object_pd =
PublicDomainObject(objectID: 436535,
                   title: "Wheat Field with Cypresses",
                   objectURL: "https://www.metmuseum.org/art/collection/search/436535",
                   primaryImageSmall: "https://images.metmuseum.org/CRDImages/ep/original/DT1567.jpg"
                   creditLine: "Purchase, The Annenberg Foundation Gift, 1993")

Below these two declarations, test for equality:

object == object_pd

Click in the margin to run the playground up to this line: In the sidebar, you get true, even though object is a MuseumObject and object_pd is a PublicDomainObject.

To make sure == isn’t just returning true all the time, the starter playground also has a second MuseumObject. If you’re continuing with your playground from the previous lesson, copy the Cypress and Poppies object from the transcript below this video to create object2:

let object2 =
MuseumObject(objectID: 13061,
             title: "Cypress and Poppies",
             objectURL: "https://www.metmuseum.org/art/collection/search/13061",
             creditLine: "Gift of Iola Stetson Haverstick, 1982",
             isPublicDomain: false)

And test for equality:

object2 == object

And it’s false, so == works!

Next, to see what an object’s default description looks like, add this line:

print(object)

Run the playground up to this line: In the sidebar, you get a string that’s not very informative.

Below the Equatable extension, add this code and let Xcode fill in the stub you need:

extension MuseumObject: CustomStringConvertible {
  var description: String {
    "\(title): \(creditLine)"
  }
}

An art object’s title and creditLine are the most meaningful pieces of information for a human reader.

Run the playground at the print(object) line: Now, you get:

Wheat Field with Cypresses: Purchase, The Annenberg Foundation Gift, 1993

And that’s how you adopt and use Equatable and CustomStringConvertible. They’ll work for any subclasses of MuseumObject, too!

You can also define your own protocols, to fine-tune your data model.

For example, an art object can be on display in the museum. Not all are — many art objects are in storage or undergoing maintenance. An art object that is on display has a non-empty string for its GalleryNumber property. Its web page has a link to show its location on a map of the museum.

Call showImage() with object2:

object2.showImage()

Run the playground and wait for the web page to appear. Scroll down to see the On view line:

Click the Gallery 774 link:

A map appears, with a Directions button. Click the button, type Van Gogh’s Cypresses, then press Return

Select the first search result and wait:

That’s a nice bit of functionality built into the website. How would you model that in your app? You’ve probably guessed that you’re not going to create an OnDisplay subclass of MuseumObject — where would that leave PublicDomainObject? The topic of this lesson is protocols, so you’re going to create an OnDisplay protocol.

Below MuseumObjectView, add this code:

protocol OnDisplay {
  var GalleryNumber: String { get }
  func showMap(from: String, to: String)
}

A data type that wants to adopt OnDisplay must have a constant property named GalleryNumber and a method with the signature showMap(from: String, to: String).

Protocols cannot require properties to be immutable, so you can’t declare GalleryNumber with let. In a protocol, you declare a read-only property as var with a { get } specifier and no { set } specifier.

Now, create an OnDisplayObject subclass of MuseumObject with a GalleryNumber property:

class OnDisplayObject: MuseumObject {
  let GalleryNumber: String

  init(objectID: Int,
       title: String,
       objectURL: String,
       creditLine: String,
       GalleryNumber: String,
       isPublicDomain: Bool) {
    self.GalleryNumber = GalleryNumber
    super.init(objectID: objectID,
               title: title,
               objectURL: objectURL,
               creditLine: creditLine,
               isPublicDomain: isPublicDomain)
  }
} 

This is like PublicDomainObject, but with GalleryNumber instead of primaryImageSmall.

Next, create an extension of OnDisplayObject and add a showMap method stub:

extension OnDisplayObject: OnDisplay {
  func showMap(from: String, to: String) {
    guard !GalleryNumber.isEmpty else { return }
    // implementation
  }
}

You check that the instance’s GalleryNumber isn’t the empty string.

OnDisplayObject inherits from the MuseumObject class and conforms to the OnDisplay protocol.

Now, create an OnDisplayObject instance:

let object_od =
OnDisplayObject(objectID: 436535,
                title: "Wheat Field with Cypresses",
                objectURL: "https://www.metmuseum.org/art/collection/search/436535",
                creditLine: "Purchase, The Annenberg Foundation Gift, 1993",
                GalleryNumber: "199",
                isPublicDomain: true)

Call showImage() with object_od and comment out object2.showImage():

object_od.showImage()

Run the playground.

OnDisplayObject is a subclass of MuseumObject, so it inherits the parent class’s showImage().

That ends this demo. Continue with the lesson for a summary.

See forum comments
Cinema mode Download course materials from Github
Previous: Instruction Next: Conclusion