如何使用其超类的实例初始化我的子类?

时间:2017-08-26 10:08:21

标签: ios swift casting subclassing eventkit

在我的应用程序中,我阅读了EKEvent类型的日历事件,并且我已经使用大量计算变量进行了扩展,因此我可以轻松获取日历中每个事件的持续时间,工时等数量。但是在大规模中,性能很差 - 所以我想使用惰性变量来缓存我所有的额外数据。

因此,我想创建一个EKEvent的子类 - 名为CustomEvent,它添加了懒惰的变量,但我的问题是EKEventStore总是返回EKEvents,我需要将它转换为我的CustomEvent子类的实例,以便能够访问懒惰的变种等。

一个简单的类型转换是不够的,我已经在操场上试过,看看哪些可行,但没有任何用处。我需要一个CustomRectangle的特殊构造函数,它可以从NativeRectangle初始化一个CustomRectangle。另一种解决方案是创建一个包装类,将原始对象保存为属性,但这不是我最喜欢的解决方案,因为我必须映射所有方法和属性

class NativeRectangle: NSObject {
    var width: Int
    var height: Int

    init(width: Int, height: Int) {
        self.width = width
        self.height = height
        super.init()
    }
}

class CustomRectangle: NativeRectangle {
    var area: Int { return width * height}
}

let rect = NativeRectangle(width: 100, height: 20)

let customRect = CustomRectangle(rect) // This fails, i need a constructor

print(customRect.area)

3 个答案:

答案 0 :(得分:4)

在创建子类实例时,Swift(通常在大多数面向对象语言中)无法使用基类对象的现有实例。

从一般的编程观点来看,在这种情况下你有两种选择:

  1. 使用合成:使CustomRectangle包含一个NativeRectangle并将所有方法转发给它。

  2. 使用地图将NativeRectangles链接到其他信息。在Objective C和Swift中,您可以使用objc_AssociationPolicy来最轻松地拥有这样的内部地图。请参阅https://stackoverflow.com/a/43056053/278842

  3. 顺便说一下。你无法从"缓存"中看到任何加速。一个简单的计算为width * height

答案 1 :(得分:0)

如果你已经在Objective-C的土地上工作,可以选择包装本机类并自动转发所有(除了添加的)消息:

- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
    NSMethodSignature *ours = [super methodSignatureForSelector:selector];
    return ours ?: [wrappedObject methodSignatureForSelector:selector];
}

我不记得这是否是转发工作所需的一切,但它应该非常接近。另外,我不知道这会如何与Swift一起玩,所以我想我们可以从Objective-C时代开始考虑这个有趣的琐事并寻找更好的解决方案......

首先想到的另一个问题是使用associated objects feature将缓存数据链接到原始实例。这样你就可以保持你的扩展方法。

答案 2 :(得分:0)

您创建了自己的CustomRectangle(object: rect),因此swift不再提供默认init()。您明确需要调用自己的属性并调用super.init(),因为您的类也继承自超类。 -

class NativeRectangle: NSObject {
    var width: Int
    var height: Int

    // Super class custom init()
    init(width: Int, height: Int) {
        self.width = width
        self.height = height
        super.init()
    }
}

class CustomRectangle: NativeRectangle {

    // computed property area
    var area: Int { return width * height}

    // Sub class Custom Init
    init(object:NativeRectangle) {
        // call to super to check proper initialization
        super.init(width: object.width, height: object.height)
    }
}

let rect = NativeRectangle(width: 100, height: 20)

let customRect = CustomRectangle(object: rect)

print(customRect.area) //2000