transportation the programming meaning lenguaje language español swift

the - swift wikipedia



¿Cómo implementar el constructor de copia en la subclase Swift? (2)

Tengo el siguiente ejemplo en un patio de Swift, en un intento de implementar un constructor de copia en 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}

El problema es que esto no se compila en su forma actual. En el método init(copyFrom: Square) en la subclase Square , se informa de este error:

Overriding method with selector ''initWithCopyFrom:'' has incompatible type ''(Square) -> Square''

Este problema tendría sentido si no fuera un constructor , como si fuera una func normal, podría pasar un tipo que se espera en la superclase, pero que se ha invalidado en la subclase para ser más restrictivo:

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.

Pero el hecho de que sea un constructor me lleva a creer que debería ser capaz de anularlo y proporcionar una firma de método diferente, ya que es absolutamente conocido en el momento de la compilación cuál es el tipo de objeto.

Este problema desaparece si NSObject Shape para que ya no se extienda NSObject . Sin embargo, debido a la inclusión con un código existente de Objective-C, necesita extender NSObject .

¿Cómo puedo actualizar mi constructor de copia para permitir que una Shape sepa que está copiando desde una Shape , y permitir que una Square sepa que está copiando desde una Shape ?


La forma más sencilla de hacerlo sería simplemente cambiar el nombre del inicializador de la subclase a init(copyFromSquare: Square) , dejando Square con el método init(copyFrom: Shape) intacto (como se ha contraído al heredar de Shape ).

Por supuesto, podría anular init(copyFrom: Shape) , y probar si copyFrom es un Square , en cuyo caso usted toma un curso de acción (establecer la longitud), de lo contrario no.

Tenga en cuenta también que debe establecer self.length antes de llamar al super.

class Shape : NSObject { var color : String override init() { color = "Red" } init(copyFrom: Shape) { color = copyFrom.color } } class Square : Shape { var length : Double override init() { self.length = 10.0 super.init() } override init(copyFrom: Shape) { if copyFrom is Square { self.length = (copyFrom as Square).length } else { self.length = 10.0 // default } super.init(copyFrom: copyFrom) } }


init(copyFrom: Square) es una sobrecarga, no una anulación, de init(copyFrom: Shape) . Lo que quiero decir es que son métodos no relacionados porque aceptan diferentes tipos. En Swift eso es aceptable. En ObjC, eso es ilegal. No hay sobrecargas en ObjC.

Los inicializadores rápidos no se heredan automáticamente. Entonces, en Swift, no podrías intentar copiar una Shape aleatoria como un Square . El inicializador no está disponible. Pero en ObjC, los inicializadores se heredan automáticamente (y no se puede evitar que lo hagan). Entonces, si tiene un método initWithCopyFrom:(*Shape) , se requiere que cada subclase esté dispuesta a aceptarlo. Eso significa que podrías (en ObjC) intentar crear una copia de un Círculo como un cuadrado. Eso es, por supuesto, sin sentido.

Si esta es una subclase de NSObject , debe usar NSCopying . Así es como harías eso:

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 3

class Shape: NSObject, NSCopying { required override init() { super.init() } func copy(with zone: NSZone? = nil) -> Any { let copy = type(of: self).init() return copy } } class Square: Shape { required override init() { super.init() } func copy(with zone: NSZone? = nil) -> Any { let copy = super.copy(with: zone) as! Square copy.foo = self.foo ...... return copy } }