I want to override properties in the following class. Say I have a class A that has a boolean property r. For the superclass A, I want r to be set and get normally. For the subclass B, I want r to always be false. I'm not sure why this is harder than it should be...
class A {
init(r: Bool) {
self.r = r
}
var r: Bool {
willSet(n) {
r = n
}
get {
return r
}
}
}
class B: A {
override var r: Bool {
willSet(n) {
r = n
}
get {
return false
}
}
}
let a = A(r: true)
a.r = false
print(a.r) // prints 'false', which is good
let b = B(r: true)
print(b.r) // prints 'true'
b.r = false // ERROR: I can't get pass this point 'Execution was interrupted on playground
print(b.r)
I agree with #Hamish: stored property in base class, with computed property override. Except, a read-only property can't override a mutable property. But, you can make the overridden setter do nothing, and the overridden getter return what you want.
class A {
init(r: Bool) {
self.r = r
}
var r: Bool
}
class B: A {
override var r: Bool {
set {}
get {
return false
}
}
}
let a = A(r: true)
print(a.r) // "true"
a.r = false
print(a.r) // "false"
let b = B(r: true)
print(b.r) // "false"
b.r = true
print(b.r) // "false"
Related
I have a custom class that I've written an equal/not equal function test for. I'm trying to test if an object I've modified is equal to the original object, but whenever I modify the second object, the original object seems to be modified as well. Here's some sample code (you can run this in a Playground):
// Custom class
class MyClass {
var foo: Bool = false
static func ==(a: MyClass, b: MyClass) -> Bool {
return (a.foo == b.foo)
}
static func !=(a: MyClass, b: MyClass) -> Bool {
return !(a==b)
}
required init() {
// do nothing
}
}
let originalObj: MyClass = MyClass()
var tempObj: MyClass = MyClass()
tempObj = originalObj
tempObj.foo = true
print(originalObj.foo) // Output: "true" (?!?!)
print(tempObj == originalObj) // Output: "true" (?!?!)
Why does changing the value of tempObj change the value of originalObj, and how can I prevent this behavior?
Classes in swift are Reference Types whereas Structs are Value Types. There are two ways to achieve what you want. You can either use struct instead of class or write a copy method for this class and use that method. Something like this
class MyClass {
var foo: Bool = false
static func ==(a: MyClass, b: MyClass) -> Bool {
return (a.foo == b.foo)
}
static func !=(a: MyClass, b: MyClass) -> Bool {
return !(a==b)
}
required init() {
// do nothing
}
func copy() -> MyClass {
let temp = MyClass()
temp.foo = foo
return temp
}
}
let originalObj: MyClass = MyClass()
var tempObj: MyClass = originalObj.copy()
I have the following structure in my iOS application:
struct MyStruct<T> {
var property1: T
var property2: T
init(property1: T, property2: T) {
self.property1 = property1
self.property2 = property2
}
init(allPropertiesWith value: T) {
self.property1 = value
self.property2 = value
}
}
I also have 2 classes that don't have a common ancestor:
class A { }
class B { }
In my application I have instances of MyStruct<A>, MyStruct<B>, MyStruct<A?>, MyStruct<B?> and I use them in these functions:
func f1(myStrurct: MyStruct<A?>) { }
func f2(myStrurct: MyStruct<A>) { }
func g2() {
f1(myStrurct: MyStruct<A?>(property2: A()))
}
/* I also have the same functions for MyStruct<B> and MyStruct<B?> */
I cannot modify f1, f2 and g2. That's why I created 2 extensions to make initialisation of MyStruct<T> easier:
extension MyStruct where T == A? {
init(property1: T) {
self.property1 = property1
self.property2 = nil
}
init(property2: T) {
self.property1 = nil
self.property2 = property2
}
}
extension MyStruct where T == B? {
init(property1: T) {
self.property1 = property1
self.property2 = nil
}
init(property2: T) {
self.property1 = nil
self.property2 = property2
}
}
As you can see these extensions are almost the same. Is it possible to refactor it with only 1 extension?
You can make both A and B (or whichever class needs it) conform to a dummy protocol and check that for T.
protocol MyStructProtocol {
}
class A: MyStructProtocol { }
class B: MyStructProtocol { }
extension MyStruct where T == MyStructProtocol? {
init(property1: T) {
self.property1 = property1
self.property2 = nil
}
init(property2: T) {
self.property1 = nil
self.property2 = property2
}
}
In the answer provided by Rakesha Shastri I found out that I can use protocol to refactor my code. However to be able to use this solution I need to rewrite other parts of my application. I tried to add the solution by Rakesha Shastri to my application and compile it with Swift 3, Swift 4 or Swift 4.2 (all Swift versions available in Xcode 10.0), but every time I received a compiler error. It means that currently there are no ways how to solve the problem that I described in this question.
You don't have to extend anything to create such an easier constructor. Check out the modified version of your struct definition below:
struct MyStruct<T> {
var property1: T?
var property2: T?
init(property1: T? = nil, property2: T? = nil) {
if T.self == String.self {
self.property1 = property1
self.property2 = nil
}
else if T.self == Int.self {
self.property1 = nil
self.property2 = property2
}
}
init(allPropertiesWith value: T) {
self.property1 = value
self.property2 = value
}
}
Then you can use initialize them as you wish with following lines.
MyStruct<String>(property2: "sadsad")
MyStruct<Int>(property1: 23)
Coming from JS, and trying to pass [JSON] by reference in swift, which is not possible, so I'm trying to wrap it in the object, and made a simple example using a primitive, which still not working, how can i wrap member a, so that changes in referenced object a affect b ? Thanks
class ExampleA {
var a = 0
init(a: Int) {
self.a = a
}
}
class ExampleB {
var a = 0
init(a: Int) {
self.a = a
}
func process(inout p: ExampleA) {
self.a = p.a
print(p.a)
}
}
var a = ExampleA(a: 15)
var b = ExampleB(a: 10)
b.process(&a)
print(b.a) // "15\n"
a.a = 25 // this does nothing to b????
print(b.a) // "15\n"
Your example fails because a is an Int, which is a value type.
When you do the assignment self.a = p.a, you're making a copy of the Int.
To achieve the reference semantics you want, you have to hold reference the ExampleA that's storing the value type. I think you got confused because of your variable naming, confusing the a : Int member of ExampleA with instances of ExampleA named a.
Here's a fix I put together. It gives ExampleB a computed property that transparently accesses the data in ExampleA.
class ExampleA {
var data = 0
init(data: Int) {
self.data = data
}
}
class ExampleB {
var a : ExampleA
var data : Int {
get {
return a.data
}
set {
a.data = newValue
}
}
init(data: Int) {
self.a = ExampleA(data: data)
}
func process(a: ExampleA) {
self.a = a
print(a.data)
}
}
var a = ExampleA(data: 15)
var b = ExampleB(data: 10)
b.process(a: a)
print(b.data) // "15\n"
a.data = 25
print(b.data) // "25\n"
Simple delegation works without any real need for inout or reference semantics:
class ExampleA {
var a = 0
init(a: Int) {
self.a = a
}
}
class ExampleB {
var aObject: ExampleA
init(a: ExampleA) {
self.aObject = a
}
func a() -> Int {
return aObject.a
}
}
var a = ExampleA(a: 15)
var b = ExampleB(a: a)
print(b.a())
a.a = 25
print(b.a())
noob question. This code has a lot of copy & paste for checking swift types. Is there a way to condense it into one generic function of some kind? Thanks for any help in advance.
import Foundation
let x: AnyObject = 42
if x is Int {
print("x is Int")
}else {
print("x is NOT Int")
}
if x is Double {
print("x is Double")
}else {
print("x is NOT Double")
}
if x is Float {
print("x is Float")
}else {
print("x is NOT Float")
}
if x is String {
print("x is String")
}else {
print("x is NOT String")
}
/*
prints:
x is Int
x is Double
x is Float
x is NOT String
*/
You can call dynamicType:
print("x is \(x.dynamicType)")
In your case, since you explicit specified that x is an object (AnyObject) it is converted to NSNumber by the compiler. Technically, it's neither Int, nor Double, nor Float.
not sure what you're doing exactly, but just using is alone should work.
let x: AnyObject = 42
x is Int // returns true
x is Double // returns true
x is Float // returns true
x is String // returns false
but if you actually need a function for some other reason, then this works the exact same.
import Foundation
func checkType(value: AnyObject, type: AnyObject) -> Bool {
if type is Int {
if value is Int {
return true
} else {
return false
}
} else if type is Double {
if value is Double {
return true
} else {
return false
}
} else if type is Float {
if value is Float {
return true
} else {
return false
}
} else if type is String {
if value is String {
return true
} else {
return false
}
}
return false
}
let myVar: AnyObject = 42
checkType(myVar, Int()) // returns true
checkType(myVar, Double()) // returns true
checkType(myVar, Float()) // returns true
checkType(myVar, String()) // returns false
ok I found the solution, it's actually quite simple:
let x = 42
func checkTypeOf<Value, Type> (value: Value, type: Type) {
if value is Type {
print("value is \(type.dynamicType)")
}else {
print("value is NOT \(type.dynamicType)")
}
}
checkTypeOf(x, type: 0)
checkTypeOf(x, type: "")
/*
prints:
value is Int
value is NOT String
*/
the thing is the "type" parameter needs to be a placeholder value, for example 0 for Int, or an empty string if checking String, so it's not the cleanest way to do it, but Swift's type inference makes it quite usable.
Class A provides a string value. Class B has two members of A type inside itself, and provide a computed property "v" to choose one of them.
class A {
var value: String
init(value: String) {
self.value = value
}
}
class B {
var v1: A?
var v2: A = A(value: "2")
private var v: A {
return v1 ?? v2
}
var value: String {
get {
return v.value
}
set {
v.value = newValue
}
}
}
This code is simple and it works. Since both the A and B have a member "value", I make it a protocol like this:
protocol ValueProvider {
var value: String {get set}
}
class A: ValueProvider {
var value: String
init(value: String) {
self.value = value
}
}
class B: ValueProvider {
var v1: ValueProvider?
var v2: ValueProvider = A(value: "2")
private var v: ValueProvider {
return v1 ?? v2
}
var value: String {
get {
return v.value
}
set {
v.value = newValue // Error: Cannot assign to the result of the expression
}
}
}
If I change the following code
v.value = newValue
to
var v = self.v
v.value = newValue
It works again!
Is this a bug of Swift, or something special for the property of protocols?
You have to define the protocol as a class protocol:
protocol ValueProvider : class {
var value: String {get set}
}
Then
var value: String {
get { return v.value }
set { v.value = newValue }
}
compiles and works as expected (i.e. assigns the new value to the
object referenced by v1 if v1 != nil, and to the object
referenced by v2 otherwise).
v is a read-only computed property of the type ValueProvider.
By defining the protocol as a class protocol the compiler knows
that v is a reference type, and therefore its v.value
property can be modified even if the reference itself is a constant.
Your initial code example works because there the v property has
the type A which is a reference type.
And your workaround
set {
var tmp = v1 ?? v2
tmp.value = newValue
}
works because (read-write) properties of variables can be set in
any case (value type or reference type).