Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Swift, does a protocol extension allow function bodies?

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

    }
}
like image 329
Laurence Wingo Avatar asked Oct 21 '25 14:10

Laurence Wingo


2 Answers

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

like image 173
M. Ullah Avatar answered Oct 24 '25 06:10

M. Ullah


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

like image 22
Vladyslav Zavalykhatko Avatar answered Oct 24 '25 06:10

Vladyslav Zavalykhatko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!