4

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

    }
}
Laurence Wingo
  • 3,912
  • 7
  • 33
  • 61
  • 1
    Read the [Protocol Extensions](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID521) section of the Swift book. – rmaddy Oct 13 '18 at 03:28
  • 1
    its not body but its default implementation or u can say optional method – SPatel Oct 13 '18 at 04:05

3 Answers3

7

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

M. Ullah
  • 96
  • 3
2

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

Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100
-1
Class -> Protocol -> Extension

Swift's protocol extension allows your class operates by additional or default functions

yoAlex5
  • 29,217
  • 8
  • 193
  • 205