I'm going through a tutorial and I noticed that the author extended their protocol called Activity and wrote the function's body in their code. This does compile however I was under the impression that protocols only show method signatures or if it does implement the body then it'll be a mutating function. The code below doesn't use mutating on one of its functions but it still runs and WORKS! Can someone explain the phenomena or confirm that protocol extensions can have method bodies?
import CareKit
import SwiftyJSON
enum ActivityType: String {
case Intervention
case Assessment
}
enum ScheduleType: String {
case Weekly
case Daily
}
enum StepFormat : String {
case Scale
case Quantity
}
protocol Activity {
var identifier : String { get set}
var groupIdentifier : String { get set}
var title : String { get set}
var colour : UIColor? { get set}
var text : String { get set}
var startDate : Date { get set}
var schedule : [NSNumber] { get set}
var scheduleType : ScheduleType { get set}
var instructions : String? { get set}
var imageURL : NSURL? { get set}
var activityType: ActivityType { get set}
var medication : Medication? { get set}
init()
init(json: JSON)
func createCareKitActivity() -> OCKCarePlanActivity
}
extension Activity {
// A mutating function to allow Acticities or Assessments to intialiser base properties
mutating func parseActivityFields(json: JSON) {
self.identifier = json["identifier"].string!
self.groupIdentifier = json["group_identifier"].string!
self.title = json["title"].string!
self.text = json["text"].string!
let colourString = json["color"].string!
self.colour = UIColor.colorWithString(colourString)
if let instructionString = json["instructions"].string {
self.instructions = instructionString
}
if let imageString = json["imageURL"].string {
let componentsOfString = imageString.components(separatedBy: ".")
if let pathForResource = Bundle.main.path(forResource: componentsOfString[0], ofType: componentsOfString[1]){
self.imageURL = NSURL(fileURLWithPath: pathForResource)
}
}
self.startDate = dateFromString(string: json["startdate"].string!)!
self.scheduleType = ScheduleType(rawValue: json["scheduletype"].string!)!
self.schedule = json["schedule"].string!.components(separatedBy: ",").map ( {
NSNumber(value: Int32($0)!)
})
if let medication = json["medication"].string,
let medicationImageString = json["medicationimage"].string {
let componentsOfString = medicationImageString.components(separatedBy: ".")
let pathForResource = Bundle.main.path(forResource: componentsOfString[0], ofType: componentsOfString[1])
self.medication = Medication.init(medication: medication, imageURL: NSURL.init(fileURLWithPath: pathForResource!))
}
}
init(json: JSON) {
self.init()
self.parseActivityFields(json: json)
}
func createCareKitActivity() -> OCKCarePlanActivity{
//creates a schedule based on the internal values for start and end dates
let startDateComponents = NSDateComponents(date: self.startDate, calendar: NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)! as Calendar)
let activitySchedule: OCKCareSchedule!
switch self.scheduleType {
case .Weekly :
activitySchedule = OCKCareSchedule.weeklySchedule(withStartDate: startDateComponents as DateComponents, occurrencesOnEachDay: self.schedule)
case .Daily:
activitySchedule = OCKCareSchedule.dailySchedule(withStartDate: startDateComponents as DateComponents, occurrencesPerDay: self.schedule[0].uintValue)
}
let activity = OCKCarePlanActivity.intervention(
withIdentifier: identifier,
groupIdentifier: nil,
title: title,
text: text,
tintColor: colour,
instructions: instructions,
imageURL: imageURL as? URL,
schedule: activitySchedule,
userInfo: ["medication": medication], optional: false)
return activity
}
}
In Swift, extensions allow you to provide default implementations for protocols.
According to the Swift documentation on Protocols,
Protocols can be extended to provide method, initializer, subscript, and computed property implementations to conforming types. This allows you to define behavior on protocols themselves, rather than in each type’s individual conformance or in a global function.
Source: Swift Documentation
In Swift, does a protocol extension allow function bodies?
Yes. It's a really convenient way to add specific functionality only to instances of some protocol. Consider this:
protocol Flying {
func useWings()
}
extension Flying {
func fly() {}
}
class Animal {}
class Bird: Animal {}
extension Bird: Flying {
func useWings() {}
}
let bird = Bird()
bird.fly()
It also makes some logic here. If something can use wings, then it also probably can fly. So when we extend Bird to implement Flying as it has useWings - it also can fly now.
The code below doesn't use mutating on one of its functions but it still runs and WORKS! Can someone explain the phenomena
Mutating keyword says that function will mutate the value it's called onto. You have to say it explicitly if your protocol is not a class (protocol Some: class {}). The createCareKitActivity() doesn't mutate self, so you don't have to specify mutating
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With