代码之家  ›  专栏  ›  技术社区  ›  Laurence Wingo

在Swift中,协议扩展是否允许功能体?

  •  1
  • Laurence Wingo  · 技术社区  · 8 年前

    我正在学习一个教程,我注意到作者扩展了他们的协议Activity,并在代码中编写了函数体。但我觉得协议只显示方法签名,或者如果它实现了主体,那么它将是一个变异函数。下面的代码没有在其中一个函数上使用mutation,但它仍然运行并工作!有人能解释这些现象吗,或者确认协议扩展可以有方法体吗?

    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
    
        }
    }
    
    2 回复  |  直到 8 年前
        1
  •  3
  •   M. Ullah    8 年前

    在Swift中,扩展允许您为协议提供默认实现。
    根据Swift关于协议的文件,

    协议可以扩展为提供方法、初始值设定项、下标、, 并将属性实现计算为一致类型。这允许 您需要定义协议本身的行为,而不是每个协议中的行为 键入单个一致性或全局函数中的一致性。

    资料来源: Swift Documentation

        2
  •  1
  •   Vladyslav Zavalykhatko    8 年前

    In Swift, does a protocol extension allow function bodies?

    对这是一种非常方便的方法,可以只在某些协议的实例中添加特定的功能。考虑一下:

    protocol Flying {
        func useWings()
    }
    
    extension Flying {
        func fly() {}
    }
    
    class Animal {}
    class Bird: Animal {}
    
    extension Bird: Flying {
        func useWings() {}
    }
    
    let bird = Bird()
    bird.fly()
    

    这里也有一些逻辑。如果有东西能用翅膀,那么它也可能会飞。所以当我们延伸 Bird 实施 Flying 事实上 useWings -它现在也能飞了。

    The code below doesn't use mutating on one of its functions but it still runs and WORKS! Can someone explain the phenomena

    Mutating关键字表示该函数将对其调用的值进行变异。如果你的协议不是一个类,你必须明确地说出来( protocol Some: class {} ).这个 createCareKitActivity() 不会变异自我,所以你不必指定 mutating

        3
  •  0
  •   yoAlex5    6 年前
    Class -> Protocol -> Extension
    

    斯威夫特 protocol extension 允许您的类通过附加或默认函数进行操作