The question is better explained in code:
class A {
class func thefunc() -> String {
/* Can I here know if thefunc was called using
A.thefunc() or
B.thefunc()?
*/
return "A" /* or "B"= */
}
}
class B: A {
}
You can use self in a static method to refer to the type (as compared to the instance for using self in an instance method)
class A {
class func thefunc() -> A.Type {
return self
}
}
class B: A { }
let metaTypeA = A.thefunc() // A.Type
let metaTypeB = B.thefunc() // B.Type
Similarly, you can use runtime introspection, specifically the subjectType property of the Mirror representation of self.
Instance Variables
...
var subjectType: Any.Type
The static type of the subject being reflected.
From the swiftdoc.org reference of Mirror structure.
E.g.:
class A {
class func thefunc() {
print(Mirror(reflecting: self).subjectType)
}
}
class B: A { }
A.thefunc() // A.Type
B.thefunc() // B.Type
Alternatively, if you needn't actually make use of the meta-type (just differ between the "static caller"), you could use the String representation of self.
class A {
class func thefunc() -> String {
return String(self)
}
}
class B: A { }
print(A.thefunc()) // A
print(B.thefunc()) // B
Related
Let us consider i have two different classes.
class A {
var something = "Hello"
}
class B {
var something = "World"
}
Now
class C {
func request() {
//Call with class A or B it can contain any class. I can call either class A or B depending on condition
update(myClass: A or B)
}
func update(myClass:A or B ) {
print(myClass.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
Plz help me achieve this using Swift
You cannot declare a function in Swift that could accept an input argument of several different types, so you cannot declare a type as A or B. However, you don't actually need this to solve your specific problem.
Since you want to access a common property of the two class instances, you should declare that property in a protocol, make both classes conform to that protocol, then make the function take an input argument of the protocol type.
protocol SomethingProtocol {
var something: String { get }
}
class A: SomethingProtocol {
let something = "Hello"
}
class B: SomethingProtocol {
let something = "World"
}
class C {
func request() {
//Call with class A or B it can contain any class. I can call either class A or B depending on condition
update(something: A())
update(something: B())
}
func update(something: SomethingProtocol) {
print(something.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
Use a protocol
protocol MyProtocol: class {
var something: String { get set }
}
class A: MyProtocol {
var something = "Hello"
}
class B: MyProtocol {
var something = "world"
}
class C {
func update(myClass:MyProtocol ) {
print(myClass.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
usage:
let a = A()
let b = B()
let c = C()
print(c.update(myClass: a))
print(c.update(myClass: b))
Output:
hello
world
Create a protocol that both A and B conforms to and use it as the parameter type in update()
protocol SomeProtocol {
var something: String {get set}
}
func update(_ o: SomeProtocol) {
print(o.something)
}
Let it be known that I think using a protocol is the cleanest option that will best solve your problem.
However, it is possible to use Any to pass any object as a parameter, this will require checking which class you are dealing with inside your update method.
Something like this...
class C {
func update(myClass: Any) {
if let a = myClass as? A {
print(a.something)
}
if let b = myClass as? B {
print(b.something)
}
}
}
This might be neater as a switch - ref
class C {
func update(myClass: Any) {
switch myClass {
case let a as A:
print(a.something)
case let b as B:
print(b.something)
default:
print("not a thing")
}
}
}
This question already has answers here:
Swift language NSClassFromString
(25 answers)
Closed 5 years ago.
Suppose I have three classes:
import Foundation
class A {
init() {
print("A")
}
}
class B {
init() {
print("B")
}
}
class C {
init() {
print("C")
}
}
I want to dinamically pass a string ("A", "B" or "C") as a function argument and then, inside the body of this function, create an instance of the class I passed. Is this possible? How?
I tried this one (and other variants) but with no luck:
func test(c:AnyObject){
let _class = c()
//...
}
test(c:A)
[UPDATE] Maybe the question is no different from the one #Code Different suggests but that question is old and there were so many changes in the language that one should try any suggested solution before finding the one that works as of today
What could work is having a base class, let's call it BaseClass. Classes that needs to be used would inherit from BaseClass.
Then, in your function, you would pass it the desired type.
Here is a code snippet that demonstrates this technique:
class BaseClass { }
class A: BaseClass { ... }
class B: BaseClass { ... }
class C: BaseClass { ... }
func test(type: BaseClass.Type) {
let someObject = type.init()
// You can cast the object if required
}
test(type: A.self) // creates an object of class A
test(type: B.self) // creates an object of class B
Edit: If you really need a string to cast your types, you might consider doing some job prior to calling test. Getting the type in a switch case and then passing it to test should do.
Edit: It would also work with a protocol, as long as it defines the initializers you need, along with every functions that must be exposed:
protocol SomeProtocol: class {
init()
func someFunction()
}
class A {
required init() {
print("A")
}
}
extension A: SomeProtocol {
func someFunction() {
print("Some function of A")
}
}
class B {
required init() {
print("B")
}
}
extension B: SomeProtocol {
func someFunction() {
print("Some function of B")
}
}
class C {
required init() {
print("C")
}
}
extension C: SomeProtocol {
func someFunction() {
print("Some function of C")
}
}
func test(someType: SomeProtocol.Type) {
let someObject: SomeProtocol = someType.init()
someObject.someFunction()
}
test(someType: A.self) // creates an object of class A
test(someType: B.self) // creates an object of class B
I have a abstract base class (DataSource, in my simplified scenario below) and a handful of subclasses (IntSource and StringSource). The base class is using generics.
I want to have a variable (say, currentDataSource) typed as the base class so it can refer to an instance of any of the subclasses. I can't figure out how to declare it, though. The declaration requires a concrete type which immediately breaks the abstraction.
class DataSource<Element> where Element:Equatable {
var elements = [Element]()
func description() {
print("must override")
}
}
class IntSource: DataSource<Int> {
override func description() {
print("Ints!")
}
}
class StringSource: DataSource<String> {
override func description() {
print("Strings!")
}
}
let a = IntSource()
let b = StringSource()
var current: DataSource<???> // this is where I'm stuck
current = a
print(current.description())
current = b
print(current.description())
I want to declare in a protocol a class func, I intend to conform to this protocol from a class A, B and C.
B and C inherit from A.
Essentially I want to override this func in B and C while still providing an implementation in A.
So, I had to declare my protocol as follows:
protocol MyManagedObjectCoolStuff {
static func entityName() -> String
}
And then I have this in A:
class A: NSManagedObject { }
class B: A { }
class C: A { }
extension A: MyManagedObjectCoolStuff {
static func entityName() -> String {
return "Animal"
}
}
extension B: MyManagedObjectCoolStuff {
override static func entityName() -> String {
return "Bat"
}
}
extension C: MyManagedObjectCoolStuff {
override static func entityName() -> String {
return "Cat"
}
}
The problem here, is clear and Xcode confirms: "Class method overrides a 'final' class method".
How can I work around this? I cannot use class func in the protocol... I'm not sure how to abstract this.
Thanks!
In a class definition, static is an alias for class final,
so it marks a type method (or property) which cannot be overridden
in subclasses.
Since you want to override the method in subclasses,
all you have to do is to define the method as class instead of static:
extension A: MyManagedObjectCoolStuff {
class func entityName() -> String {
return "Animal"
}
}
extension B: MyManagedObjectCoolStuff {
override class func entityName() -> String {
return "Bat"
}
}
extension C: MyManagedObjectCoolStuff {
override class func entityName() -> String {
return "Cat"
}
}
Alternatively one could use the fact that for a Core Data entity,
the class name is usually defined as <ModuleName>.<EntityName>
so that the entity name is the last component of the class name.
So you could define entityName() as an
extension method of NSManagedObject (the superclass of all Core Data
object classes) as in How can I create instances of managed object subclasses in a NSManagedObject Swift extension?:
extension NSManagedObject {
class func entityName() -> String {
let classString = NSStringFromClass(self)
// The entity is the last component of dot-separated class name:
let components = split(classString) { $0 == "." }
return components.last ?? classString
}
}
and override it only where necessary:
class A: NSManagedObject { }
class B: A { }
class C: A { }
extension C {
override class func entityName() -> String {
return "Cat"
}
}
println(A.entityName()) // A
println(B.entityName()) // B
println(C.entityName()) // Cat
Right now I have the following classes:
class A {
class func instantiate() -> A {
return MakeObject()
}
}
class B: A {}
let x = B.instantiate()
This results in x being of type A. How can I change instantiate in order to return an instance of the subclass that was called from? In other words, so that x ends up being of type B.
EDIT:
This is what I used to solve it, based on Martin R's answers:
class A {
class func instantiate() -> Self {
func helper<T>() -> T {
return MakeObject() as! T
}
return helper()
}
}
The returns type needs to be Self (which is the concrete type when
the class method is called), and initialization must be done with a
required init method (which can be overridden in a subclass):
class A {
class func instantiate() -> Self {
return self.init()
}
required init() {
}
}
class B: A {}
let x = B.instantiate() // `x` has type `B`
Alternatively, just define an init method
init(parameters ...) {
}
which "automatically" returns instances of the class that is is
called on.