【问题标题】:In Swift, does a protocol extension allow function bodies?在 Swift 中,协议扩展是否允许函数体?
【发布时间】:2018-10-13 03:23:59
【问题描述】:

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

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

    }
}

【问题讨论】:

  • 阅读 Swift 书籍的Protocol Extensions 部分。
  • 它不是主体,而是它的默认实现,或者你可以说可选方法

标签: swift swift-protocols swift-extensions


【解决方案1】:

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

可以扩展协议以提供方法、初始化器、下标、 以及符合类型的计算属性实现。这允许 您可以在协议本身上定义行为,而不是在每个 类型的个体一致性或在全局函数中。

来源:Swift Documentation

【讨论】:

    【解决方案2】:

    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】:
      Class -> Protocol -> Extension
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-04
        • 1970-01-01
        • 2017-04-24
        • 1970-01-01
        相关资源
        最近更新 更多