While this code is technically fine and will work, as Flambino has pointed out, it's rather pointless and with the fact that play()
is called in didStartPlaying()
it's a bit confusing. I know that's an implementation detail and doesn't have anything to do with the protocol necessarily, however, it does hint at a lack of understanding of protocols/delegates.
There's not a lot out there in the way of Swift code. However, there is a lot out there in the way of Objective-C code. And in Objective-C, there's heavy use of the protocol-delegate pattern as well.
The same Foundation protocol/delegate patterns exist exactly as they are in Objective-C also in Swift, it's just a different syntax. But the method names are all basically the same, and you can definitely pick up on the very distinct naming pattern and get the idea of how protocol/delegate patterns work.
The most common protocol/delegate pattern in iOS development is that of the UITableViewDelegate
and UITableViewDataSource
(something similar probably exists for NSTableView
in OSX). Almost everyone who has done much of an iOS programming has at some point worked with a UITableView
.
What actually makes a lot more sense in this case is for PlayableMedia
to be a superclass. BlueRayMedia
and DVDMedia
should be subclasses of PlayableMedia
... and these objects should be delegated.
What would make a lot of sense would be something like this:
protocol PlayableMediaDelegate {
func shouldBeginPlaying() -> Bool
func willBeginPlaying()
func didBeginPlaying()
func shouldStopPlaying() -> Bool
func willStopPlaying()
func didStopPlaying()
}
Now the media has a delegate
property, which is simply an AnyObject
that conforms to the PlayableMediaDelegate
protocol.
Any object can call play()
on the PlayableMedia
object, and then the play method would actually look something like this:
func play() {
if delegate.shouldBeginPlaying() {
delegate.willBeginPlaying()
println("PlayableMedia is now playing...")
delegate.didBeginPlaying()
}
}
And stop()
would look something like this:
func stop() {
if delegate.shouldStopPlaying() {
delegate.willStopPlaying()
println("PlayableMedia has stopped playing...")
delegate.didStopPlaying()
}
}
Where in both cases the println()
code is replaced with code that would actually start/stop the playable media from playing.
The point here is with these delegate methods, we let ANY OBJECT delegate our playable media. The shouldBeginPlaying()
and shouldStopPlaying()
methods give our delegate a chance to prevent/allow that action from happening. If the delegate returns false
from this method, the action isn't taken.
The other methods just let our delegate know about the life cycle of the media starting/stopping.
Some examples of things that you might want to do in these delegate methods...
In shouldBeginPlaying()
, you may check the media's age restrictions and decide not to play the media. You may also check the device battery life, etc. Any condition in which you might not want to play the media, your delegate can just return false
from this method to prevent the action from happening.
In willStopPlaying()
, the delegate may want to save the current position in the media so that it can be resumed later. The PlayableMedia
class probably shouldn't necessarily do keep track of where it left of last time.
In willBeginPlaying()
, you might want to call some methods on the PlayableMedia
object to finish setting it up for getting played. Perhaps moving to the point in which was last left off.
The main idea here is that we're writing a class that we want to allow delegation by any sort of unknown object. What you shouldn't do when designing a protocol is start by writing the class you intend to use as the delegate, then write a protocol to match that class, then write the class that needs to be delegated by the first class--that's backwards.
didStartPlaying
gets called before the actual media actually gets played; if anything it should be opposite - and then delegates could come in handy. None of that is specific to Swift though; the same would apply if this was ObjC (or anything else, really). – Flambino Jul 1 '14 at 12:09