Swift中如何从EKEvent实例初始化其子类Event?
问题解答
首先明确:继承EKEvent来实现你的需求是走不通的,原因如下:
EKEvent是EventKit框架提供的系统类,从日历获取的实例由框架内部创建,Swift/Objective-C没有机制能将一个已存在的父类实例直接转换为其子类实例。子类的初始化必须调用父类的指定初始化器(比如init(eventStore:)),但这类初始化器是用来创建新事件的,无法接收一个已有的EKEvent实例来复制它的所有属性——EKEvent包含大量私有/只读的内部状态,你无法完全手动复制,强行做不仅繁琐,还会在系统更新类结构时出现兼容问题。
你的组合方案才是最优解
你当前用的组合模式是处理这类系统类扩展需求的标准做法,比继承更灵活、更低耦合。可以优化一下封装,让调用更简洁:
class Event { // 自定义扩展属性 public var matiere: String = "" public var matiereId: String = "" public var prof: String = "" public var salle: String = "" public var type: String = "" // 私有持有系统EKEvent实例,避免外部直接修改 private let ekEvent: EKEvent // 封装常用属性,简化调用(不用每次写ekEvent.xxx) public var startDate: Date { ekEvent.startDate } public var endDate: Date { ekEvent.endDate } public var title: String? { ekEvent.title } public var calendar: EKCalendar? { ekEvent.calendar } // 时长相关属性改为计算属性,避免存储冗余数据 public var duration: DateInterval { DateInterval(start: ekEvent.startDate, end: ekEvent.endDate) } public var hoursDuration: Int { Int(duration.duration) / 3600 } public var minutesDuration: Int { (Int(duration.duration) - 3600 * hoursDuration) / 60 } init(ekEvent: EKEvent) { self.ekEvent = ekEvent } }
极端场景的替代方案(不推荐)
如果一定要给EKEvent直接附加属性,可通过Objective-C关联对象实现“伪存储属性”,但这属于hack写法,存在内存风险且不符合Swift设计风格,仅适合少量属性的场景:
import ObjectiveC // 关联对象的唯一标识Key private var MatiereKey: UInt8 = 0 private var MatiereIdKey: UInt8 = 1 extension EKEvent { var matiere: String { get { objc_getAssociatedObject(self, &MatiereKey) as? String ?? "" } set { objc_setAssociatedObject(self, &MatiereKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } } var matiereId: String { get { objc_getAssociatedObject(self, &MatiereIdKey) as? String ?? "" } set { objc_setAssociatedObject(self, &MatiereIdKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) } } // 其他自定义属性同理 }
总结
建议继续使用你的组合方案,它是解决这类问题的可靠选择,逻辑清晰且易于维护。
内容的提问来源于stack exchange,提问作者M3tex
相关产品推荐
相关产品推荐

