Create instance of class based on function argument [duplicate] - swift

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

Related

How can i pass class as a parameter to a function in Swift?

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")
}
}
}

Protocol extensions not using most specific implementation

I have two classes, Object and SubObject. A protocol, MyProtocol, has an associatedtype of type Object. In two extensions, I have provided implementations of the save function. When I create an instance of TestClass with either of the classes, they both result in a call to the least specific extension implementation, while it would be expected to call the most specific one.
class Object {}
class SubObject: Object {}
protocol MyProtocol {
associatedtype T: Object
func save()
}
extension MyProtocol {
func save() {
print("Object")
}
}
extension MyProtocol where T == SubObject {
func save() {
print("SubObject")
}
}
class MyClass<T: Object>: MyProtocol {
}
class TestClass<T: Object> {
typealias U = MyClass<T>
func test() {
let myClass = U()
myClass.save()
}
}
let testClass1 = TestClass<Object>()
testClass1.test() // returns "Object"
let testClass2 = TestClass<SubObject>()
testClass2.test() // returns "Object" (should be "SubObject")
How can I solve this, so that the TestClass calls the correct implementation of save? Or is this not currently possible in Swift? Any help would be appreciated!

variable of a base class that uses generics

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())

Any way to get the calling class on static functions in Swift?

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

How can I override superclass property with different type

As title.
I know. I can use [AnyObject] instead of type variable, But I just want to prevent a lots of type checking in swift.
And now, I don't have any idea about this problem. Does anyone can help me. Thanks
class TypeA: NSObject {
var name: String
........
}
class TypeB: TypeA {
.........
}
class ObjectA {
var type = [TypeA]()
}
class ObjectB: ObjectA {
override var type = [TypeB]() <---Cannot override a property "type"
}
Question update: Thanks guys and reference to "R Menke"'s code
class TypeA: NSObject {
override init() {
print("typeA")
}
}
class TypeB: TypeA {
override init() {
print("typeB")
}
}
class ObjectA<T:TypeA> {
var type = [T]()
init(type:T) {
self.type.append(type)
print("objectA")
}
func addNewType() {
let newType = TypeA()
self.type.append(newType) <-- compiler complaints at here
}
}
class ObjectB<T:TypeA>: ObjectA<T> {
override init(type:T) {
super.init(type: type)
print("objectB")
}
}
You can make ObjectA and ObjectB generic classes.
class ObjectA<T:TypeA> {
var type = [T]()
Now the type attribute will always be a TypeA or a subclass of TypeA.
But you no longer need to downcast to find out what type it is.
class TypeA: NSObject {
override init() {
print("typeA")
}
}
class TypeB: TypeA {
override init() {
print("typeB")
}
}
class ObjectA<T:TypeA> {
var type = [T]()
init(type:T) {
self.type.append(type)
print("objectA")
}
}
class ObjectB<T:TypeA>: ObjectA<T> {
override init(type:T) {
super.init(type: type)
print("objectB")
}
}
let tA = TypeA()
let tB = TypeB()
let oA = ObjectA(type: tA) // ObjectA<TypeA>
let oB = ObjectB(type: tB) // ObjectB<TypeB>
Or just make ObjectA generic :
ObjectB will now work as a specialiser for ObjectA, it is not generic itself, but does put a constraint on it's superclass. Now you can use it like any other class but it's type property will have TypeB as type instead of TypeA
class ObjectA<T:TypeA> {
var type = [T]()
init(type:T) {
self.type.append(type)
print("objectA")
}
}
class ObjectB: ObjectA<TypeB> {
override init(type:TypeB) {
super.init(type: type)
print("objectB")
}
}
#RMenke is completely correct here, but it's also important to understand why it's true. This isn't a limitation of Swift. This is a fundamental issue of what subclasses mean.
Let's pretend for a moment that you could do what you're asking for. If that were true, the following code would be legal:
let objA: ObjectA = ObjectB()
objA.type.append(ObjectA())
I have to be allowed to treat ObjectB as if it were an ObjectA. That's what the Liskov Substitution Principle means for subtyping. So now I'm allowed to add an ObjectA to an [ObjectB]. That breaks the whole type system. Blam.
Generally when you want this, it's because you're misusing subclasses. Subclasses are seldom the right tool in pure Swift; they mostly creep in because of bridging to ObjC. But even in ObjC, subclassing should be avoided when possible. Swift brings us excellent new tools to help avoid subclasses, and you should prefer them. For example, rather than subclassing, just use protocols:
protocol A {}
struct TypeA: A {}
struct TypeB: A {}
class Object<T: A> {
var type = [T]()
}
You are not allowed to override a stored property in swift. However, you are allowed to change the value of an inherited property while initialising an Instance.
Example:
class TypeA: NSObject {
}
class TypeB: TypeA {
}
class ObjectA {
var type = [TypeA]()
}
class ObjectB: ObjectA {
override init() {
super.init()
type = [TypeB]()
}
}
Another option, would be to use one Class within the other instead of using inheritance. Something like this:
class TypeA: NSObject {
}
class TypeB: TypeA {
}
class ObjectA {
var type = [TypeA]()
}
class ObjectB: NSObject {
private var obj = ObjectA()
var type: [TypeB] {
get{
return obj.type as! [TypeB]
}
set {
obj.type = newValue
}
}
}
var obj1 = ObjectB()
obj1.type = [TypeB()]
let test: TypeB = obj1.type[0]