Unable to understand behaviour of inheritance in swift? - ios

I have created a parent class which has one property. Now i'm inheriting this class into my child class. It is obvious that member of parent class will become member of child class. So, when i change the value in child class, the same variable value is also getting changed in parent class.
I have used below mentioned code.
class SomeClass {
var avar:String = "Hello"
var bvar:String?
func someFunc() {
}
}
class Bclass:SomeClass {
func myFunc() {
self.avar = "Bye"
super.avar
}
}
let c = Bclass()
c.myFunc() // "Bye"
let d = SomeClass()
d.someFunc() // "Hello"
Here output is Bye but it should be Hello as i'm not changing parent class member value. When i access with instance of SomeClass then it shows output as Hello
Few questions-
Does it make copy of parent class variable in child class or refrence?
super means i want to access variable of parent class then why value changed ?
EDIT: As per Frankie answer
In below scenario why it still prints "Hello".
class SomeClass {
var avar:String = "Hello"
var bvar:String?
func someFunc() {
self.avar
}
}
class Bclass:SomeClass {
func myFunc() {
self.avar = "Bye"
super.avar
self.avar
}
}
class Cclass:SomeClass {
func myFunc() {
super.avar
self.avar
}
}
let c = Bclass()
c.myFunc()
let d = SomeClass()
d.someFunc()
let e = Cclass()
e.myFunc()

When you create an instance with let c = Bclass() there is one and only one instance created. There is no 'super instance' that is additionally created, so the notion of copying or reference doesn't make sense.
The subclass merely inherits all the properties and functions of the super class, or more plainly, it inherits only what defines the super class. Therefore self.avar and super.avar are the exact same thing.
Example:
class SomeClass {
var avar: String = "Hello"
}
class Bclass: SomeClass {
//imagine there is a (var avar: String = "Hello") here because it was defined in the super class
func myFunc() {
print(super.avar) //prints 'Hello'
self.avar = "Bye"
print(super.avar) //prints 'bye'
}
}
EDIT
From the OP's edit:
let c = Bclass()
c.myFunc() //assigns self.avar = "Bye", therefore prints "Bye"
let d = SomeClass()
d.someFunc() //does not make any assignment in someFunc, therefore prints the assigned value of "Hello"
let e = Cclass()
e.myFunc() //does not make any assignment in myFunc, therefore 'e' looks to its
//superclass for the value since it was never overridden and prints "Hello"
//It does NOT look to 'c' for the value because 'c' is a completely separate instance

A subclass takes all of the properties, function and methods of its superclass. The superclass is some kind of starting place / foundation for a subclass.
For instance, when you create a normal ViewController, you define it as:
class mySubclass: UIViewController{
// UIViewController's variables, properties, methods, functions...
// your code
}
You can imagine that all of the code from the superclass now lies inside the subclass as well. A good example of usage might be:
class Person{
var name: String = ""
var age: Int = 0
var job: String? = ""
}
class John: Person {
self.name = "John" // equivalent of super.name
self.age = 26
self.job = "Programmer"
}
You can say that the second class is some kind of customisation for the superclass, copying and changing its properties.

Related

Swift/Combine- Assign a filtered object to a property on a class

I have a list of objects.
let arr = [[1, 2, 3, 4, 5]]
It lives in a repository.
class ArrayRepository: ObservableObject {
#Published let arr = [1,2,3,4,5]
}
I have a class with a property that needs it assigned at initialization.
class MyClass: ObservableObject {
var id: String = ""
var myProperty: Int?
}
My class is created through an asynchronous process that is itself a repository.
class myClassRepository {
func buildClass -> MyClass {
myClassInstance = MyClass()
self.arrayRepository.$arr.map { arr in
arr.filter{ $0 == someOther.Value }
}.assign(to: \.myProperty, on: myClassInstance).store(in: &subscriptions)
return myClassInstance
}
}
The problem is my pattern returns an array of elements that I cant make conform to to the singular property on the class? Whats the best way to get it out?
The error I get is essentially
Declared closure result '[Int]' is incompatible with contextual type 'Int??'
Due to a limitation of Swift's type system, you cannot currently assign to an Optional property with a non-Optional value. You can, however, create your own version of assign that does:
func assign<Root: AnyObject>(to path: ReferenceWritableKeyPath<Root, Output?>, on root: Root) -> AnyCancellable {
sink { [weak root] in root?[keyPath: path] = $0 }
}
This implementation also has the bonus of preventing a reference cycle.

Swift - How to pair variables from two Independent classes?

Imagine we have two classes A and B. A is a nonspeciffic class and B is a subclass of a ViewController
How to make B instance variable equal to A instance variable?
A class cannot hold an instance of B, and mutually B cannot hold an instance of A.
The exact thing I'd like to achieve is that B class variable is updated to the value of A class variable.
Delegation is not possible because none of the classes holds the other's instance.
How should I approach such problem? KVO? I read that it rather shouldn't be used due to its flaws.
If neither class can hold a reference to the other one, they both need to hold a reference to an object of a third class, which holds the actual value. Properties inside A and B need to reference the corresponding property in C:
class C {
var prop : String = "hello"
}
class A {
var prop : String {
get { return c.prop }
set(v:String) { c.prop = v }
}
let C:c
init(c:C) {
self.c = c
}
}
class B : NSViewController {
var prop : String {
get { return c.prop }
set(v:String) { c.prop = v }
}
let C:c
init(c:C) {
self.c = c
}
}
KVO or NSNotification are your options. Consider using a lib such as KVOController
Try to read it

How do I type check, without including subclasses? [duplicate]

When trying to understand a program, or in some corner-cases, it's useful to find out what type something is. I know the debugger can show you some type information, and you can usually rely on type inference to get away with not specifying the type in those situations, but still, I'd really like to have something like Python's type()
dynamicType (see this question)
Update: this has been changed in a recent version of Swift, obj.dynamicType now gives you a reference to the type and not the instance of the dynamic type.
This one seems the most promising, but I haven't been able to find out the actual type so far.
class MyClass {
var count = 0
}
let mc = MyClass()
# update: this now evaluates as true
mc.dynamicType === MyClass.self
I also tried using a class reference to instantiate a new object, which does work, but oddly gave me an error saying I must add a required initializer:
works:
class MyClass {
var count = 0
required init() {
}
}
let myClass2 = MyClass.self
let mc2 = MyClass2()
Still only a small step toward actually discovering the type of any given object though
edit: I've removed a substantial number of now irrelevant details - look at the edit history if you're interested :)
Swift 3 version:
type(of: yourObject)
Swift 2.0:
The proper way to do this kind of type introspection would be with the Mirror struct,
let stringObject:String = "testing"
let stringArrayObject:[String] = ["one", "two"]
let viewObject = UIView()
let anyObject:Any = "testing"
let stringMirror = Mirror(reflecting: stringObject)
let stringArrayMirror = Mirror(reflecting: stringArrayObject)
let viewMirror = Mirror(reflecting: viewObject)
let anyMirror = Mirror(reflecting: anyObject)
Then to access the type itself from the Mirror struct you would use the property subjectType like so:
// Prints "String"
print(stringMirror.subjectType)
// Prints "Array<String>"
print(stringArrayMirror.subjectType)
// Prints "UIView"
print(viewMirror.subjectType)
// Prints "String"
print(anyMirror.subjectType)
You can then use something like this:
if anyMirror.subjectType == String.self {
print("anyObject is a string!")
} else {
print("anyObject is not a string!")
}
The dynamicType.printClassName code is from an example in the Swift book. There's no way I know of to directly grab a custom class name, but you can check an instances type using the is keyword as shown below. This example also shows how to implement a custom className function, if you really want the class name as a string.
class Shape {
class func className() -> String {
return "Shape"
}
}
class Square: Shape {
override class func className() -> String {
return "Square"
}
}
class Circle: Shape {
override class func className() -> String {
return "Circle"
}
}
func getShape() -> Shape {
return Square() // hardcoded for example
}
let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true
Note: that subclasses of NSObject already implement their own className function. If you're working with Cocoa, you can just use this property.
class MyObj: NSObject {
init() {
super.init()
println("My class is \(self.className)")
}
}
MyObj()
As of Xcode 6.0.1 (at least, not sure when they added it), your original example now works:
class MyClass {
var count = 0
}
let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`
Update:
To answer the original question, you can actually use the Objective-C runtime with plain Swift objects successfully.
Try the following:
import Foundation
class MyClass { }
class SubClass: MyClass { }
let mc = MyClass()
let m2 = SubClass()
// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))
If you simply need to check whether the variable is of type X, or that it conforms to some protocol, then you can use is, or as? as in the following:
var unknownTypeVariable = …
if unknownTypeVariable is <ClassName> {
//the variable is of type <ClassName>
} else {
//variable is not of type <ClassName>
}
This is equivalent of isKindOfClass in Obj-C.
And this is equivalent of conformsToProtocol, or isMemberOfClass
var unknownTypeVariable = …
if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
//unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
//unknownTypeVariable is not of type <ClassName or ProtocolName>
}
Swift 3:
if unknownType is MyClass {
//unknownType is of class type MyClass
}
For Swift 3.0
String(describing: <Class-Name>.self)
For Swift 2.0 - 2.3
String(<Class-Name>)
Here is 2 ways I recommend doing it:
if let thisShape = aShape as? Square
Or:
aShape.isKindOfClass(Square)
Here is a detailed example:
class Shape { }
class Square: Shape { }
class Circle: Shape { }
var aShape = Shape()
aShape = Square()
if let thisShape = aShape as? Square {
println("Its a square")
} else {
println("Its not a square")
}
if aShape.isKindOfClass(Square) {
println("Its a square")
} else {
println("Its not a square")
}
Old question, but this works for my need (Swift 5.x):
print(type(of: myObjectName))
Comment: I don't see how #JérémyLapointe answers the question. Using type(of:) only works by checking the compile-time information even if the actual type is a more specific subclass. There is now an easier way to dynamically query the type in Swift 5.1 without resorting to dynamicType like #Dash suggests. For more details on where I got this information, see SE-0068: Expanding Swift Self to class members and value types.
Code
Swift 5.1
// Within an instance method context
Self.self
// Within a static method context
self
This allows the use of Self as shorthand for referring to the containing type (in the case of structs, enums, and final class) or the dynamic type (in the case of non-final classes).
Explanation
The proposal explains well why this approach improves on dynamicType:
Introducing Self addresses the following issues:
dynamicType remains an exception to Swift's lowercased keywords rule. This change eliminates a special case that's out of step with
Swift's new standards. Self is shorter and clearer in its intent. It
mirrors self, which refers to the current instance.
It provides an easier way to access static members. As type names grow large, readability suffers.
MyExtremelyLargeTypeName.staticMember is unwieldy to type and read.
Code using hardwired type names is less portable than code that automatically knows its type.
Renaming a type means updating any TypeName references in code. Using self.dynamicType fights against Swift's goals of concision and
clarity in that it is both noisy and esoteric.
Note that self.dynamicType.classMember and TypeName.classMember
may not be synonyms in class types with non-final members.
If you get an "always true/fails" warning you may need to cast to Any before using is
(foo as Any) is SomeClass
If a parameter is passed as Any to your function, you can test on a special type like so :
func isADate ( aValue : Any?) -> Bool{
if (aValue as? Date) != nil {
print ("a Date")
return true
}
else {
print ("This is not a date ")
return false
}
}
Depends on the use case. But let's assume you want to do something useful with your "variable" types. The Swift switch statement is very powerful and can help you get the results you're looking for...
let dd2 = ["x" : 9, "y" : "home9"]
let dds = dd2.filter {
let eIndex = "x"
let eValue:Any = 9
var r = false
switch eValue {
case let testString as String:
r = $1 == testString
case let testUInt as UInt:
r = $1 == testUInt
case let testInt as Int:
r = $1 == testInt
default:
r = false
}
return r && $0 == eIndex
}
In this case, have a simple dictionary that contains key/value pairs that can be UInt, Int or String. In the .filter() method on the dictionary, I need to make sure I test for the values correctly and only test for a String when it's a string, etc. The switch statement makes this simple and safe!
By assigning 9 to the variable of type Any, it makes the switch for Int execute. Try changing it to:
let eValue:Any = "home9"
..and try it again. This time it executes the as String case.
//: Playground - noun: a place where people can play
import UIKit
class A {
class func a() {
print("yeah")
}
func getInnerValue() {
self.dynamicType.a()
}
}
class B: A {
override class func a() {
print("yeah yeah")
}
}
B.a() // yeah yeah
A.a() // yeah
B().getInnerValue() // yeah yeah
A().getInnerValue() // yeah

Swift: subscript for array with custom type

I have a class, MyClass, and in another class I have a global variable array:
var myArray:[MyClass]
In MyClass I don't have any array.
Now, if I want to do this:
for index in 0..10 {
self.myArray[index] = //a new object
}
I get an error that MyClass doesn't have a subscript. Any thoughts on why? Remember that MyClass doesn't have any arrays in it.
Some more code to show you what I mean:
class TheirClass {
var myArray: [MyClass] = [] // or use an initializer
func test() -> Void {
for index in 0..10 {
self.myArray[index] = MyClass()
}
}
}
class MyClass {
var prop1 = ""
var prop2 = 0
}
If you are calling a var from another class you would have to address it like I do below:
class TheirClass {
var myArray: [MyClass] = [] // or use an initializer
}
class MyClass {
var objectArray = TheirClass().myArray
}
Not sure if this is what you planned to do or not. Let me know and I can alter the code to fit your purpose.
You have .. in the code which doesn't exist in Swift. You probably meant ... but there is ..< as well.
However, you have an array of size zero in your initializer, which means that you can't add values to it. You'll either have to create a new array of the right size first of all, or append to it using myArray += [MyClass()].
Also note that the -> Void is unnecessary - if you don't have a return type, it will implicitly be a void type.

How do you find out the type of an object (in Swift)?

When trying to understand a program, or in some corner-cases, it's useful to find out what type something is. I know the debugger can show you some type information, and you can usually rely on type inference to get away with not specifying the type in those situations, but still, I'd really like to have something like Python's type()
dynamicType (see this question)
Update: this has been changed in a recent version of Swift, obj.dynamicType now gives you a reference to the type and not the instance of the dynamic type.
This one seems the most promising, but I haven't been able to find out the actual type so far.
class MyClass {
var count = 0
}
let mc = MyClass()
# update: this now evaluates as true
mc.dynamicType === MyClass.self
I also tried using a class reference to instantiate a new object, which does work, but oddly gave me an error saying I must add a required initializer:
works:
class MyClass {
var count = 0
required init() {
}
}
let myClass2 = MyClass.self
let mc2 = MyClass2()
Still only a small step toward actually discovering the type of any given object though
edit: I've removed a substantial number of now irrelevant details - look at the edit history if you're interested :)
Swift 3 version:
type(of: yourObject)
Swift 2.0:
The proper way to do this kind of type introspection would be with the Mirror struct,
let stringObject:String = "testing"
let stringArrayObject:[String] = ["one", "two"]
let viewObject = UIView()
let anyObject:Any = "testing"
let stringMirror = Mirror(reflecting: stringObject)
let stringArrayMirror = Mirror(reflecting: stringArrayObject)
let viewMirror = Mirror(reflecting: viewObject)
let anyMirror = Mirror(reflecting: anyObject)
Then to access the type itself from the Mirror struct you would use the property subjectType like so:
// Prints "String"
print(stringMirror.subjectType)
// Prints "Array<String>"
print(stringArrayMirror.subjectType)
// Prints "UIView"
print(viewMirror.subjectType)
// Prints "String"
print(anyMirror.subjectType)
You can then use something like this:
if anyMirror.subjectType == String.self {
print("anyObject is a string!")
} else {
print("anyObject is not a string!")
}
The dynamicType.printClassName code is from an example in the Swift book. There's no way I know of to directly grab a custom class name, but you can check an instances type using the is keyword as shown below. This example also shows how to implement a custom className function, if you really want the class name as a string.
class Shape {
class func className() -> String {
return "Shape"
}
}
class Square: Shape {
override class func className() -> String {
return "Square"
}
}
class Circle: Shape {
override class func className() -> String {
return "Circle"
}
}
func getShape() -> Shape {
return Square() // hardcoded for example
}
let newShape: Shape = getShape()
newShape is Square // true
newShape is Circle // false
newShape.dynamicType.className() // "Square"
newShape.dynamicType.className() == Square.className() // true
Note: that subclasses of NSObject already implement their own className function. If you're working with Cocoa, you can just use this property.
class MyObj: NSObject {
init() {
super.init()
println("My class is \(self.className)")
}
}
MyObj()
As of Xcode 6.0.1 (at least, not sure when they added it), your original example now works:
class MyClass {
var count = 0
}
let mc = MyClass()
mc.dynamicType === MyClass.self // returns `true`
Update:
To answer the original question, you can actually use the Objective-C runtime with plain Swift objects successfully.
Try the following:
import Foundation
class MyClass { }
class SubClass: MyClass { }
let mc = MyClass()
let m2 = SubClass()
// Both of these return .Some("__lldb_expr_35.SubClass"), which is the fully mangled class name from the playground
String.fromCString(class_getName(m2.dynamicType))
String.fromCString(object_getClassName(m2))
// Returns .Some("__lldb_expr_42.MyClass")
String.fromCString(object_getClassName(mc))
If you simply need to check whether the variable is of type X, or that it conforms to some protocol, then you can use is, or as? as in the following:
var unknownTypeVariable = …
if unknownTypeVariable is <ClassName> {
//the variable is of type <ClassName>
} else {
//variable is not of type <ClassName>
}
This is equivalent of isKindOfClass in Obj-C.
And this is equivalent of conformsToProtocol, or isMemberOfClass
var unknownTypeVariable = …
if let myClass = unknownTypeVariable as? <ClassName or ProtocolName> {
//unknownTypeVarible is of type <ClassName or ProtocolName>
} else {
//unknownTypeVariable is not of type <ClassName or ProtocolName>
}
Swift 3:
if unknownType is MyClass {
//unknownType is of class type MyClass
}
For Swift 3.0
String(describing: <Class-Name>.self)
For Swift 2.0 - 2.3
String(<Class-Name>)
Here is 2 ways I recommend doing it:
if let thisShape = aShape as? Square
Or:
aShape.isKindOfClass(Square)
Here is a detailed example:
class Shape { }
class Square: Shape { }
class Circle: Shape { }
var aShape = Shape()
aShape = Square()
if let thisShape = aShape as? Square {
println("Its a square")
} else {
println("Its not a square")
}
if aShape.isKindOfClass(Square) {
println("Its a square")
} else {
println("Its not a square")
}
Old question, but this works for my need (Swift 5.x):
print(type(of: myObjectName))
Comment: I don't see how #JérémyLapointe answers the question. Using type(of:) only works by checking the compile-time information even if the actual type is a more specific subclass. There is now an easier way to dynamically query the type in Swift 5.1 without resorting to dynamicType like #Dash suggests. For more details on where I got this information, see SE-0068: Expanding Swift Self to class members and value types.
Code
Swift 5.1
// Within an instance method context
Self.self
// Within a static method context
self
This allows the use of Self as shorthand for referring to the containing type (in the case of structs, enums, and final class) or the dynamic type (in the case of non-final classes).
Explanation
The proposal explains well why this approach improves on dynamicType:
Introducing Self addresses the following issues:
dynamicType remains an exception to Swift's lowercased keywords rule. This change eliminates a special case that's out of step with
Swift's new standards. Self is shorter and clearer in its intent. It
mirrors self, which refers to the current instance.
It provides an easier way to access static members. As type names grow large, readability suffers.
MyExtremelyLargeTypeName.staticMember is unwieldy to type and read.
Code using hardwired type names is less portable than code that automatically knows its type.
Renaming a type means updating any TypeName references in code. Using self.dynamicType fights against Swift's goals of concision and
clarity in that it is both noisy and esoteric.
Note that self.dynamicType.classMember and TypeName.classMember
may not be synonyms in class types with non-final members.
If you get an "always true/fails" warning you may need to cast to Any before using is
(foo as Any) is SomeClass
If a parameter is passed as Any to your function, you can test on a special type like so :
func isADate ( aValue : Any?) -> Bool{
if (aValue as? Date) != nil {
print ("a Date")
return true
}
else {
print ("This is not a date ")
return false
}
}
Depends on the use case. But let's assume you want to do something useful with your "variable" types. The Swift switch statement is very powerful and can help you get the results you're looking for...
let dd2 = ["x" : 9, "y" : "home9"]
let dds = dd2.filter {
let eIndex = "x"
let eValue:Any = 9
var r = false
switch eValue {
case let testString as String:
r = $1 == testString
case let testUInt as UInt:
r = $1 == testUInt
case let testInt as Int:
r = $1 == testInt
default:
r = false
}
return r && $0 == eIndex
}
In this case, have a simple dictionary that contains key/value pairs that can be UInt, Int or String. In the .filter() method on the dictionary, I need to make sure I test for the values correctly and only test for a String when it's a string, etc. The switch statement makes this simple and safe!
By assigning 9 to the variable of type Any, it makes the switch for Int execute. Try changing it to:
let eValue:Any = "home9"
..and try it again. This time it executes the as String case.
//: Playground - noun: a place where people can play
import UIKit
class A {
class func a() {
print("yeah")
}
func getInnerValue() {
self.dynamicType.a()
}
}
class B: A {
override class func a() {
print("yeah yeah")
}
}
B.a() // yeah yeah
A.a() // yeah
B().getInnerValue() // yeah yeah
A().getInnerValue() // yeah

Resources