swift 3 downcast to dynamic class - swift

I am trying to create a couple of objects which are dependent one to each other and they mush have a method to downcast directly the concrete class of the other object. Something like this:
protocol aProt
{
var bVar:bProt! { get set }
}
protocol bProt
{
var aVar:aProt! { get set }
}
class a: aProt
{
var bVar: bProt!
func bConcrete() -> b {
return bVar as! b
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete() -> a {
return aVar as! a
}
Now, the problem is that I want this behavior (func aConcrete(),func bConcrete()) to be inherited by the subclasses of a and b. Then I thought the perfect way of doing this was using generics, but... There's no way of doing this.
class a: aProt
{
var bVar: bProt!
func bConcrete() -> T {
return bVar as! T
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete<T>() -> T {
return aVar as! T
}
You can do it but when you have to use it you must downcast the variable anyway, so there is no way of doing it in a clean manner:
let aObject = a()
let bSubclassObject = a.bConcrete() // The compiler complains it cannot infer the class of T
let bSubclassObject = a.bConcrete() as! bSubclass // this works, but this is exactly which I wanted to avoid... :(

Define the generic function and add where to T:
protocol aProt {
var bVar: bProt! { get set }
}
protocol bProt {
var aVar:aProt! { get set }
}
class a: aProt {
var bVar: bProt!
func bConcrete<T: b>(_ type: T.Type) -> T? {
return bVar as? T
}
}
class b: bProt {
var aVar: aProt!
func aConcrete<T: a>(_ type: T.Type) -> T? {
return aVar as? T
}
}
class a1: a { }
class b1: b {
var fullName: String = "new object"
}
let aObj = a()
aObj.bVar = b1()
let bObj = aObj.bConcrete(b1.self)
bObj?.fullName
According to your requirement, calls bConcrete(b1.self) might still not good enough, but at least you need to know what type of data you are expecting to return.

Related

Get different class types by `var` from inherited objects

I need to get different class types by var from inherited objects. and I need these objects to be not generic. something like this
import Foundation
protocol MyClassProtocol {
associatedtype MyClass: Any
var myClass: MyClass.Type { get }
}
extension MyClassProtocol {
var myClass: MyClass.Type {
get { Self.MyClass.self }
}
}
class A: MyClassProtocol {
typealias MyClass = String
}
class B: A {
typealias MyClass = Int64
}
let a = A().myClass // String.Type
let a1 = A.MyClass.self // String.Type
let b = B().myClass // String.Type
let b1 = B.MyClass.self // Int64.Type
let list: [A] = [A(),B()]
// any way, how i get from this list different classes?
let la = list[0].myClass // String.Type
let la1 = type(of: list[0]).MyClass.self // String.Type
let lb = list[1].myClass // String.Type
let lb1 = type(of: list[1]).MyClass.self // String.Type
how I can resolve it? I cant use generic because I have array: [A]
If you want to achieve this kind of functionality, you will have store the class type as an instance variable and utilize class types that conform to AnyClass aka AnyObject.Type like below.
There is no practical reason to do this, and it is highly discouraged, but if you want to call something like classB.staticMethod() this is how you would do it.
class MyCustomClass: NSObject {
#objc
static func myStaticMethod() { print("why the heck do i need this?") }
}
protocol MyClassProtocol {
var myClass: AnyClass { get }
}
class A: MyClassProtocol {
var myClass: AnyClass { return NSString.self }
}
class B: A {
override var myClass: AnyClass { return MyCustomClass.self }
}
var list: [MyClassProtocol] = [A(), B()]
let classA: AnyClass = list[0].myClass.self // NSString
let classB: AnyClass = list[1].myClass.self // MyCustomClass
if classB.responds(to: #selector(MyCustomClass.myStaticMethod)) {
classB.performSelector(inBackground: #selector(MyCustomClass.myStaticMethod),
with: nil)
}

Can a Swift Property Wrapper reference the owner of the property its wrapping?

From within a property wrapper in Swift, can you someone refer back to the instance of the class or struck that owns the property being wrapped? Using self doesn't obviously work, nor does super.
I tried to pass in self to the property wrapper's init() but that doesn't work either because self on Configuration is not yet defined when #propertywrapper is evaluated.
My use case is in a class for managing a large number of settings or configurations. If any property is changed, I just want to notify interested parties that something changed. They don't really need to know which value just, so use something like KVO or a Publisher for each property isn't really necessary.
A property wrapper looks ideal, but I can't figure out how to pass in some sort of reference to the owning instance that the wrapper can call back to.
References:
SE-0258
enum PropertyIdentifier {
case backgroundColor
case textColor
}
#propertyWrapper
struct Recorded<T> {
let identifier:PropertyIdentifier
var _value: T
init(_ identifier:PropertyIdentifier, defaultValue: T) {
self.identifier = identifier
self._value = defaultValue
}
var value: T {
get { _value }
set {
_value = newValue
// How to callback to Configuration.propertyWasSet()?
//
// [self/super/...].propertyWasSet(identifier)
}
}
}
struct Configuration {
#Recorded(.backgroundColor, defaultValue:NSColor.white)
var backgroundColor:NSColor
#Recorded(.textColor, defaultValue:NSColor.black)
var textColor:NSColor
func propertyWasSet(_ identifier:PropertyIdentifier) {
// Do something...
}
}
The answer is no, it's not possible with the current specification.
I wanted to do something similar. The best I could come up with was to use reflection in a function at the end of init(...). At least this way you can annotate your types and only add a single function call in init().
fileprivate protocol BindableObjectPropertySettable {
var didSet: () -> Void { get set }
}
#propertyDelegate
class BindableObjectProperty<T>: BindableObjectPropertySettable {
var value: T {
didSet {
self.didSet()
}
}
var didSet: () -> Void = { }
init(initialValue: T) {
self.value = initialValue
}
}
extension BindableObject {
// Call this at the end of init() after calling super
func bindProperties(_ didSet: #escaping () -> Void) {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if var child = child.value as? BindableObjectPropertySettable {
child.didSet = didSet
}
}
}
}
You cannot do this out of the box currently.
However, the proposal you refer to discusses this as a future direction in the latest version:
https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#referencing-the-enclosing-self-in-a-wrapper-type
For now, you would be able to use a projectedValue to assign self to.
You could then use that to trigger some action after setting the wrappedValue.
As an example:
import Foundation
#propertyWrapper
class Wrapper {
let name : String
var value = 0
weak var owner : Owner?
init(_ name: String) {
self.name = name
}
var wrappedValue : Int {
get { value }
set {
value = 0
owner?.wrapperDidSet(name: name)
}
}
var projectedValue : Wrapper {
self
}
}
class Owner {
#Wrapper("a") var a : Int
#Wrapper("b") var b : Int
init() {
$a.owner = self
$b.owner = self
}
func wrapperDidSet(name: String) {
print("WrapperDidSet(\(name))")
}
}
var owner = Owner()
owner.a = 4 // Prints: WrapperDidSet(a)
My experiments based on : https://github.com/apple/swift-evolution/blob/master/proposals/0258-property-wrappers.md#referencing-the-enclosing-self-in-a-wrapper-type
protocol Observer: AnyObject {
func observableValueDidChange<T>(newValue: T)
}
#propertyWrapper
public struct Observable<T: Equatable> {
public var stored: T
weak var observer: Observer?
init(wrappedValue: T, observer: Observer?) {
self.stored = wrappedValue
}
public var wrappedValue: T {
get { return stored }
set {
if newValue != stored {
observer?.observableValueDidChange(newValue: newValue)
}
stored = newValue
}
}
}
class testClass: Observer {
#Observable(observer: nil) var some: Int = 2
func observableValueDidChange<T>(newValue: T) {
print("lol")
}
init(){
_some.observer = self
}
}
let a = testClass()
a.some = 4
a.some = 6
The answer is yes! See this answer
Example code for calling ObservableObject publisher with a UserDefaults wrapper:
import Combine
import Foundation
class LocalSettings: ObservableObject {
static var shared = LocalSettings()
#Setting(key: "TabSelection")
var tabSelection: Int = 0
}
#propertyWrapper
struct Setting<T> {
private let key: String
private let defaultValue: T
init(wrappedValue value: T, key: String) {
self.key = key
self.defaultValue = value
}
var wrappedValue: T {
get {
UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.set(newValue, forKey: key)
}
}
public static subscript<EnclosingSelf: ObservableObject>(
_enclosingInstance object: EnclosingSelf,
wrapped wrappedKeyPath: ReferenceWritableKeyPath<EnclosingSelf, T>,
storage storageKeyPath: ReferenceWritableKeyPath<EnclosingSelf, Setting<T>>
) -> T {
get {
return object[keyPath: storageKeyPath].wrappedValue
}
set {
(object.objectWillChange as? ObservableObjectPublisher)?.send()
UserDefaults.standard.set(newValue, forKey: object[keyPath: storageKeyPath].key)
}
}
}

Swift 3. Cast Any to class which conforms specific protocol

I have a random protocol as example
protocol testP {
init(param1: String)
}
And I have a class, which take Any as parameter as example:
class testC {
var aClass: Any
}
How can I check if aClass conforms to protocol testP and if it does, create a new object using protocol initializer, as example:
let newObject = aClass(param1: "Hello World!")
Please, help
You can test it as other type checking with if-let:
protocol TestP {
init(param1: String)
}
class TestC {
var aClass: Any
init(_ aClass: Any) {
self.aClass = aClass
}
}
class MyClassA: TestP {
required init(param1: String) {
//
}
}
class MyClassB {
}
let containerA = TestC(MyClassA.self)
let containerB = TestC(MyClassB.self)
if let testPType = containerA.aClass as? TestP.Type {
var a = testPType.init(param1: "abc")
print(a) //->MyClassA
}
if let testPType = containerB.aClass as? TestP.Type {
print("This print statement is not executed")
}
By the way, if you assign only class types to aClass, consider using AnyClass or Any.Type.

Swift: How to retrieve different type and named primary keys from generic memory stores?

I have two protocols and two objects that implement them. One object uses name:String as its primary key, the other uses code:Int.
protocol AlphaProtocol{
var name:String {get set}
init(name: String)
}
protocol BetaProtocol{
var code: Int {get set}
init(code:Int)
}
class AlphaObject: AlphaProtocol{
var name: String
required init(name: String){
self.name = name
}
}
class BetaObject: BetaProtocol{
var code: Int
required init(code: Int){
self.code = code
}
}
Right now, to store the these objects I use two different memory stores that implement two different protocols, one for each kind of object.
protocol AlphaStoreProtocol{
func addObject(object anObject: AlphaProtocol)
func getObject(name aName:String)->AlphaProtocol?
func removeObject(name aName: String)
}
protocol BetaStoreProtocol{
func addObject(object anObject: BetaProtocol)
func getObject(code aCode:Int)->BetaProtocol?
func removeObject(code aCode: Int)
}
class AlphaStore{
fileprivate var objects = [AlphaProtocol]()
func addObject(object anObject: AlphaProtocol){
if getObject(name: anObject.name) == nil{
objects.append(anObject)
}
}
func getObject(name aName:String)->AlphaProtocol?{
for o in objects{
if o.name == aName{
return o
}
}
return nil
}
func removeObject(name aName: String){
self.objects = self.objects.filter({$0.name != aName})
}
}
class BetaStore: BetaStoreProtocol{
fileprivate var objects = [BetaProtocol]()
func addObject(object anObject: BetaProtocol){
if getObject(code: anObject.code) == nil{
objects.append(anObject)
}
}
func getObject(code aCode:Int)->BetaProtocol?{
for o in objects{
if o.code == aCode{
return o
}
}
return nil
}
func removeObject(code aCode: Int){
self.objects = self.objects.filter({$0.code != aCode})
}
}
Test Code using two tailor made stores.
let alpha = AlphaObject(name: "Alpha")
let beta = BetaObject(code: 12345)
let alphaStore = AlphaStore()
let betaStore = BetaStore()
alphaStore.addObject(object: alpha)
if (alphaStore.getObject(name: alpha.name) != nil){
print("alpha object has been added to alphaStore")
}
alphaStore.removeObject(name: alpha.name)
if (alphaStore.getObject(name: alpha.name) == nil){
print("alpha object has been removed from alphaStore")
}
betaStore.addObject(object: beta)
if (betaStore.getObject(code: beta.code) != nil){
print("beta object has been added to betaStore")
}
betaStore.removeObject(code: beta.code)
if (betaStore.getObject(code: beta.code) == nil){
print("beta object has been removed from betaStore")
}
The goal: using a single generic class for both the stores but I'm stuck because the two objects use two different primary keys (different type and different name) and I can't simply force a generic "Id" as the primary key in the objects. One has to be named "name" and the other "code".
Is there a way to write the getObject and removeObject methods to accept both kind of objects?
protocol GenericStoreProtocol{
associatedtype T
func addObject(object anObject: T)
// func getObject()->T // One object use a name:String, the other code:Int as its primary key!
// func removeObject() // One object use a name:String, the other code:Int as its primary key!
}
class GenericStore<T>: GenericStoreProtocol{
fileprivate var objects = [T]()
func addObject(object anObject: T){
objects.append(anObject)
}
// ...
}
let genericAlphaStore = GenericStore<AlphaProtocol>()
let genericBetaStore = GenericStore<BetaProtocol>()
To generalize the problem, we need a store that can:
add items of any types (or ones we specify)
look up and delete items by id
use the correct id property for different stored objects
First, I'd create a protocol called Storable which has an identifier computed property. This should be of type Equatable as we will eventually be using equality comparisons when looking up objects by id in our Store.
protocol Storable {
associatedtype Identifier: Equatable
var identifier: Identifier { get }
}
We can now define the classes of the objects we are going to store (AlphaObject and BetaObject). Both of these classes should conform to their own protocol as well as the Stored protocol. Here is where you'd define what property should be used as the identifier. For AlphaObject it's name and for BetaObject it's code. These can be read-only computed properties that return the values of name and code respectively.
protocol AlphaProtocol {
var name: String { get set }
init(name: String)
}
protocol BetaProtocol {
var code: Int { get set }
init(code: Int)
}
class AlphaObject: AlphaProtocol, Storable {
typealias Identifier = String
internal var identifier: Identifier {
return self.name
}
var name: String
required init(name: String) {
self.name = name
}
}
class BetaObject: BetaProtocol, Storable {
typealias Identifier = Int
internal var identifier: Identifier {
return self.code
}
var code: Int
required init(code: Int){
self.code = code
}
}
Finally, our Store will take any objects that are Storable and will access, insert, and delete based on T's specified identifier.
class Store<T: Storable> {
fileprivate var objects = [T]()
func addObject(object: T) {
if getObject(identifier: object.identifier) == nil {
objects.append(object)
}
}
func getObject(identifier: T.Identifier) -> T? {
for o in objects {
if o.identifier == identifier {
return o
}
}
return nil
}
func removeObject(identifier: T.Identifier) {
self.objects = self.objects.filter({$0.identifier != identifier})
}
}
The full code with tests!
protocol Storable {
associatedtype Identifier: Equatable
var identifier: Identifier { get }
}
protocol AlphaProtocol {
var name: String { get set }
init(name: String)
}
protocol BetaProtocol {
var code: Int { get set }
init(code: Int)
}
class AlphaObject: AlphaProtocol, Storable {
typealias Identifier = String
internal var identifier: Identifier {
return self.name
}
var name: String
required init(name: String) {
self.name = name
}
}
class BetaObject: BetaProtocol, Storable {
typealias Identifier = Int
internal var identifier: Identifier {
return self.code
}
var code: Int
required init(code: Int){
self.code = code
}
}
class Store<T: Storable> {
fileprivate var objects = [T]()
func addObject(object: T) {
if getObject(identifier: object.identifier) == nil {
objects.append(object)
}
}
func getObject(identifier: T.Identifier) -> T? {
for o in objects {
if o.identifier == identifier {
return o
}
}
return nil
}
func removeObject(identifier: T.Identifier) {
self.objects = self.objects.filter({$0.identifier != identifier})
}
}
/* Tests */
let alpha = AlphaObject(name: "Alpha")
let beta = BetaObject(code: 12345)
let alphaStore = Store<AlphaObject>()
let betaStore = Store<BetaObject>()
alphaStore.addObject(object: alpha)
if (alphaStore.getObject(identifier: alpha.name) != nil){
print("alpha object has been added to alphaStore")
}
alphaStore.removeObject(identifier: alpha.name)
if (alphaStore.getObject(identifier: alpha.name) == nil){
print("alpha object has been removed from alphaStore")
}
betaStore.addObject(object: beta)
if (betaStore.getObject(identifier: beta.code) != nil){
print("beta object has been added to betaStore")
}
betaStore.removeObject(identifier: beta.code)
if (betaStore.getObject(identifier: beta.code) == nil){
print("beta object has been removed from betaStore")
}
I can't simply force a generic "Id" as the primary key in the objects.
Yep, you totally can if you use a single protocol instead of two unrelated ones (AlphaProtocol and BetaProtocol).
protocol KeyedObject {
associatedtype PrimaryKey : Equatable
var key: PrimaryKey { get }
}
Just make your objects conform to this protocol; they can declare whatever equatable type you require for the key, they just have to provide some way to access it.
class AlphaObject: KeyedObject {
typealias PrimaryKey = String
var name: String
required init(name: String) {
self.name = name
}
var key: String {
return self.name
}
}
Then you can use a straightforward generic class that contains only objects you provided:
class GenericStore<T : KeyedObject> {
fileprivate var objects = [T]()
func addObject(object anObject: T){
objects.append(anObject)
}
func getObject(key: T.PrimaryKey) -> T? {
for o in objects{
if o.key == key {
return o
}
}
return nil
}
...
}

Implementing copy() in Swift

I want to be able to copy a custom class in Swift. So far, so good. In Objective-C I just had to implement the NSCopying protocol, which means implementing copyWithZone.
As an example, I have a basic class called Value which stores a NSDecimalNumber.
func copyWithZone(zone: NSZone) -> AnyObject! {
return Value(value: value.copy() as NSDecimalNumber)
}
In Objective-C I, could easily just call copy to copy my object. In Swift, there seems to be no way to call copy. Do I really need to call copyWithZone even if no zone is needed? And which zone do I need to pass as a parameter?
The copy method is defined in NSObject. If your custom class does not inherit from NSObject, copy won't be available.
You can define copy for any object in the following way:
class MyRootClass {
//create a copy if the object implements NSCopying, crash otherwise
func copy() -> Any {
guard let asCopying = ((self as AnyObject) as? NSCopying) else {
fatalError("This class doesn't implement NSCopying")
}
return asCopying.copy(with: nil)
}
}
class A : MyRootClass {
}
class B : MyRootClass, NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
return B()
}
}
var b = B()
var a = A()
b.copy() //will create a copy
a.copy() //will fail
I guess that copy isn't really a pure Swift way of copying objects. In Swift it is probably a more common way to create a copy constructor (an initializer that takes an object of the same type).
Well, there is a really easy solution for this and you do not have to create root class.
protocol Copyable {
init(instance: Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(instance: self)
}
}
Now, if you want to make your custom class be able to copy, you have to conform it to Copyable protocol and provide init(instance: Self) implementation.
class A: Copyable {
var field = 0
init() {
}
required init(instance: A) {
self.field = instance.field
}
}
Finally, you can use func copy() -> Self on any instance of A class to create a copy of it.
let a = A()
a.field = 1
let b = a.copy()
You can just write your own copy method
class MyRootClass {
var someVariable:Int
init() {
someVariable = 2
}
init(otherObject:MyRootClass) {
someVariable = otherObject.someVariable
}
func copy() -> MyRootClass {
return MyRootClass(self)
}
}
The benefit of this is when you are using subclasses around your project, you can call the 'copy' command and it will copy the subclass. If you just init a new one to copy, you will also have to rewrite that class for each object...
var object:Object
....
//This code will only work for specific class
var objectCopy = Object()
//vs
//This code will work regardless of whether you are using subClass or superClass
var objectCopy = object.copy()
In my case the object chain was large and nested so was looking for simpler solutions.
The core concept being simple enough... duplicate the data by new initialization, I used Encode and Decode to deep-copy the entire object since my objects were already conforming to Codable,
Simple Example:
class MyCodableObject: Codable, CustomStringConvertible {
var name: String
var description: String { name }
init(name: String) {
self.name = name
}
}
let originalArr = [MyCodableObject(name: "a"),
MyCodableObject(name: "b")]
do {
let data = try JSONEncoder().encode(originalArr)
let copyArr = try JSONDecoder().decode([MyCodableObject].self, from: data)
//modify if required
copyArr.forEach { obj in
obj.name = "\(obj.name) modified"
}
print(originalArr, copyArr) //-> [a, b] [a modified, b modified]
} catch {
fatalError(error.localizedDescription)
}
Refactor (Generic Solution):
To simplify future cases we can create a protocol that will provide a copy function.
For Non-Codable objects, you will have to implement your own copy function.
For Codable objects, we can provide a default implementation so it's ready-to-use. Like so:
protocol Copyable {
func copy() -> Self
}
extension Copyable where Self: Codable {
func copy() -> Self {
do {
let encoded = try JSONEncoder().encode(self)
let decoded = try JSONDecoder().decode(Self.self, from: encoded)
return decoded
} catch {
fatalError(error.localizedDescription)
}
}
}
We can now conform a Codable object to our Copyable protocol and start using it immediately.
extension MyCodableObject: Copyable {}
Example:
let a = MyCodableObject(name: "A")
let b = a.copy()
b.name = "B"
print(a.name, b.name) //-> "A B"
We can also conform an Array of Codable objects to Copyable and access the copy function instantly:
extension Array: Copyable where Element: Codable {}
Example:
let originalArr = [MyCodableObject(name: "a"),
MyCodableObject(name: "b")]
let copyArr = originalArr.copy()
copyArr.forEach { (obj) in
obj.name = "\(obj.name) modified"
}
print(originalArr, copyArr) //-> [a, b] [a modified, b modified]
IMO, the simplest way to achieve this is :
protocol Copyable
{
init(other: Self)
}
extension Copyable
{
func copy() -> Self
{
return Self.init(other: self)
}
}
Implemented in a struct as :
struct Struct : Copyable
{
var value: String
init(value: String)
{
self.value = value
}
init(other: Struct)
{
value = other.value
}
}
And, in a class, as :
class Shape : Copyable
{
var color: NSColor
init(color: NSColor)
{
self.color = color
}
required init(other: Shape)
{
color = other.color
}
}
And in subclasses of such a base class as :
class Circle : Shape
{
var radius: Double = 0.0
init(color: NSColor, radius: Double)
{
super.init(color: color)
self.radius = radius
}
required init(other: Shape)
{
super.init(other: other)
if let other = other as? Circle
{
radius = other.radius
}
}
}
class Square : Shape
{
var side: Double = 0.0
init(color: NSColor, side: Double)
{
super.init(color: color)
self.side = side
}
required init(other: Shape)
{
super.init(other: other)
if let other = other as? Square
{
side = other.side
}
}
}
If you want to be able to copy an array of Copyable types :
extension Array where Element : Copyable
{
func copy() -> Array<Element>
{
return self.map { $0.copy() }
}
}
Which then allows you to do simple code like :
{
let shapes = [Circle(color: .red, radius: 5.0), Square(color: .blue, side: 5.0)]
let copies = shapes.copy()
}
In my opinion, more Swifty way is to use associated type in Copyable protocol which allows define return type for method copy. Other ways don't allow to copy an object tree like this:
protocol Copyable {
associatedtype V
func copy() -> V
func setup(v: V) -> V
}
class One: Copyable {
typealias T = One
var name: String?
func copy() -> V {
let instance = One()
return setup(instance)
}
func setup(v: V) -> V {
v.name = self.name
return v
}
}
class Two: One {
var id: Int?
override func copy() -> Two {
let instance = Two()
return setup(instance)
}
func setup(v: Two) -> Two {
super.setup(v)
v.id = self.id
return v
}
}
extension Array where Element: Copyable {
func clone() -> [Element.V] {
var copiedArray: [Element.V] = []
for element in self {
copiedArray.append(element.copy())
}
return copiedArray
}
}
let array = [One(), Two()]
let copied = array.clone()
print("\(array)")
print("\(copied)")
Copyable instances in swift
NOTE:
The great thing about this approach to copying Class instances is that it doesn't rely on NSObject or objc code, and most importantly it doesn't clutter up the "Data-Style-Class". Instead it extends the protocol that extends the "Data-Style-Class". This way you can compartmentalize better by having the copy code in another place than the data it self. The inheritance between classes is also taken care of as long as you model the protocols after the classes. Here is an example of this approach:
protocol IA{var text:String {get set}}
class A:IA{
var text:String
init(_ text:String){
self.text = text
}
}
extension IA{
func copy() -> IA {
return A(text)
}
}
protocol IB:IA{var number:Int {get set}}
class B:A,IB{
var number:Int
init(_ text:String, _ number:Int){
self.number = number
super.init(text)
}
}
extension IB{
func copy() -> IB {
return B(text,number)
}
}
let original = B("hello",42)
var uniqueCopy = original.copy()
uniqueCopy.number = 15
Swift.print("uniqueCopy.number: " + "\(uniqueCopy.number)")//15
Swift.print("original.number: " + "\(original.number)")//42
NOTE:
To see an implementation of this approach in real code: Then check out this Graphic Framework for OSX: (PERMALINK) https://github.com/eonist/Element/wiki/Progress2#graphic-framework-for-osx
The different shapes uses the same style but each style uses a style.copy() call to create an unique instance. Then a new gradient is set on this copy rather than on the original reference like this:
The code for the above example goes like this:
/*Gradients*/
let gradient = Gradient(Gradients.red(),[],GradientType.Linear,π/2)
let lineGradient = Gradient(Gradients.teal(0.5),[],GradientType.Linear,π/2)
/*Styles*/
let fill:GradientFillStyle = GradientFillStyle(gradient);
let lineStyle = LineStyle(20,NSColorParser.nsColor(Colors.green()).alpha(0.5),CGLineCap.Round)
let line = GradientLineStyle(lineGradient,lineStyle)
/*Rect*/
let rect = RectGraphic(40,40,200,200,fill,line)
addSubview(rect.graphic)
rect.draw()
/*Ellipse*/
let ellipse = EllipseGraphic(300,40,200,200,fill.mix(Gradients.teal()),line.mix(Gradients.blue(0.5)))
addSubview(ellipse.graphic)
ellipse.draw()
/*RoundRect*/
let roundRect = RoundRectGraphic(40,300,200,200,Fillet(50),fill.mix(Gradients.orange()),line.mix(Gradients.yellow(0.5)))
addSubview(roundRect.graphic)
roundRect.draw()
/*Line*/
let lineGraphic = LineGraphic(CGPoint(300,300),CGPoint(500,500),line.mix(Gradients.deepPurple()))
addSubview(lineGraphic.graphic)
lineGraphic.draw()
NOTE:
The copy call is actually done in the mix() method. This is done so that code can be more compact and an instance is conveniently returned right away.
PERMALINK for all the supporting classes for this example: https://github.com/eonist/swift-utils
Only if you are using ObjectMapper library :
do like this
let groupOriginal = Group(name:"Abc",type:"Public")
let groupCopy = Mapper<Group>().mapAny(group.toJSON())! //where Group is Mapable
Swift making copies of passed class instances
If you use the code in the accepted answer(the OP answered their own question) here, so long as your class is a subclass of NSObject and uses the Copying protocol in that post it will work as expected by calling the copyOfValues() function.
With this, no tedious setup or copy functions where you need to assign all the instance variables to the new instance.
I should know, I wrote that code and just tested it XD