如何在Swift子类中实现复制构造函数?

前端之家收集整理的这篇文章主要介绍了如何在Swift子类中实现复制构造函数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我在 Swift游乐场中有以下示例,试图在Swift中实现一个复制构造函数
class Shape : NSObject {
    var color : String

    override init() {
        color = "Red"
    }

    init(copyFrom: Shape) {
        color = copyFrom.color
    }
}

class Square : Shape {
    var length : Double

    override init() {
        super.init()
        length = 10.0
    }

    init(copyFrom: Square) { /* Compilation error here! */
        super.init(copyFrom: copyFrom)
        length = copyFrom.length
    }
}

let s : Square = Square()      // {{color "Red"} length 10.0}

let copy = Square(copyFrom: s) // {{color "Red"} length 10.0}

s.color = "Blue"               // {{color "Blue"} length 10.0}
s                              // {{color "Blue"} length 10.0}
copy                           // {{color "Red"} length 10.0}

问题在于,它并不会以当前的形式实际编译.在Square子类的init(copyFrom:Square)方法中,会报告此错误

使用选择器’initWithCopyFrom:’的覆盖方法具有不兼容的类型'(Square) – >广场’

如果它不是一个构造函数,这个问题是有道理的,就像它是一个常规的函数一样,你可以传递一个超类中的预期类型,但是这个类被覆盖在更多的限制性中:

let mySquare : Shape = Square()  // Note the var is a SHAPE
mySquare.someShapeMethod("Test") // If Square overrides someShapeMethod() to expect Int,compiler errors out to protect us here.

但是,这是一个构造函数,我相信我应该能够覆盖它并提供一个不同的方法签名,因为在编译时绝对知道对象的类型.

如果我改变Shape不再扩展NSObject,则此问题消失.然而,由于包含了现有的Objective-C代码,它需要扩展NSObject.

如何更新我的复制构造函数以允许Shape知道它是从Shape中复制的,并允许Square知道从Square复制?

init(copyFrom:Square)是init(copyFrom:Shape)的重载,而不是覆盖.我的意思是他们是不相关的方法,因为他们接受不同的类型.在斯威夫特这是可以接受的.在ObjC中,这是非法的. ObjC中没有超载.

Swift初始化器不会自动继承.所以在Swift中,你不能尝试将随机的Shape复制成Square.初始化程序不可用.但是在ObjC中,初始化器会自动继承(并且您不能阻止它们这样做).所以如果你有一个方法initWithCopyFrom:(* Shape),则需要每个子类都愿意接受它.这意味着你可以(在ObjC中)尝试创建一个Circle作为Square的副本.这当然是废话.

如果这是一个NSObject子类,你应该使用NSCopying.这是你会怎么做的:

import Foundation

class Shape : NSObject,NSCopying { // <== Note NSCopying
  var color : String

  required override init() { // <== Need "required" because we need to call dynamicType() below
    color = "Red"
  }

  func copyWithZone(zone: NSZone) -> AnyObject { // <== NSCopying
    // *** Construct "one of my current class". This is why init() is a required initializer
    let theCopy = self.dynamicType()
    theCopy.color = self.color
    return theCopy
  }
}

class Square : Shape {
  var length : Double

  required init() {
    length = 10.0
    super.init()
  }

  override func copyWithZone(zone: NSZone) -> AnyObject { // <== NSCopying
    let theCopy = super.copyWithZone(zone) as Square // <== Need casting since it returns AnyObject
    theCopy.length = self.length
    return theCopy
  }

}

let s = Square()      // {{color "Red"} length 10.0}

let copy = s.copy() as Square // {{color "Red"} length 10.0} // <== copy() requires a cast

s.color = "Blue"               // {{color "Blue"} length 10.0}
s                              // {{color "Blue"} length 10.0}
copy                           // {{color "Red"}

猜你在找的Swift相关文章