Generic class doesn't call overridden initializer - swift

class Gen<T: A> {
func create() -> T {
if T.self is B.Type {
println("YES")
}
return T(id: "cool")
}
}
class A {
let id: String
init(id: String) {
self.id = id
println("class A \(id)")
}
}
class B: A {
override init(id: String) {
println("class B \(id)")
super.init(id: id)
}
}
let coll = Gen<B>()
let t = coll.create()
output is
"YES"
"class A cool"
There is no output from overridden B.init.
Is that a compiler bug? Do I need to do it differently?
Xcode 6.1

That looks like a compiler bug.
If you try:
NSStringFromClass(t.dynamicType)
it (playground) outputs something like:
__lldb_expr_781.A
so t is of type A. More interestingly:
let t: B = coll.create()
doesn't generate any compilation error, but it's a huge compilation mistake, because if the instance is of type A, it cannot be assigned to a variable of type B (because B is a subclass of A, but the opposite is possible thanks to polymorphism).
To prove that: add any property to the B class, like:
var x = 0
if you try accessing it:
t.x
a runtime error is reported (EXC_BAD_ACCESS).
Also read this Q/A, it's a similar problem (if not the same)

You need to make initializers required, then add let realType = T.self line to create() method and replace T() with realType().
class Gen<T: A> {
func create() -> T {
let realType = T.self
return realType(id: "cool")
}
}
class A {
let id: String
required init(id: String) {
self.id = id
println("class A \(id)")
}
}
class B: A {
required init(id: String) {
println("class B \(id)")
super.init(id: id)
}
}
let coll = Gen<B>()
let t = coll.create()

Related

How to write generic function which the implementation access the property of type

I am trying to write a generic function in the the body of the function, it reads one of the property of the Type.
My function:
func doSomething<Key>(
_ key: Key
) -> Int {
let a = key.aProperty
return doSomethingElse(a)
}
and I have put different struct to doSomething as long as they have the 'aProperty' as one of its properties
struct A {
let a : String
let aProperty: String
}
struct B {
let b : String
let aProperty: String
}
let a = A()
let b = B()
doSomething<A>(a)
doSomething<B>(b)
But I get compiler error in my doSomething function saying 'Value of type 'Key' has no member 'aProperty' .
So can you please tell me what am I missing in defining my doSomething function?
You can use protocol.
func doSomethingElse(_ a: String) -> Int { 0 }
protocol HasAProperty {
var aProperty: String { get }
}
func doSomething<Key: HasAProperty>(
_ key: Key
) -> Int {
let a = key.aProperty
return doSomethingElse(a)
}
struct A: HasAProperty {
let a : String
let aProperty: String
}
struct B: HasAProperty {
let b : String
let aProperty: String
}
let a = A(a: "a", aProperty: "aProperty")
let b = B(b: "b", aProperty: "aProperty")
doSomething(a)
doSomething(b)

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

Different return types from protocol method

I would like to have a protocol that defines some methods and properties. However, property types and method return types may vary between the different classes that conform to said protocol. For example: A.getContent() may return a value of type String, but B.getContent() may return a value of type Int. In my example below, I used the type Any. Is this possible in Swift or is this a totally wrong approach? Maybe with generics?
protocol Content {
func getContent() -> any
}
class A: Content {
func getContent() -> String {
return "Im a String"
}
}
class B: Content {
func getContent() -> Int {
return 1234
}
}
I think you are looking about Generics in Protocol.
You can associate a type dynamically with associatedtype, for example
protocol Content{
associatedtype T
func getContent()-> T
}
class A: Content {
func getContent() -> String {
return "Hello World"
}
}
class B: Content {
func getContent() -> Int {
return 42
}
}
A().getContent() //"Hello World"
B().getContent() //42
If you look at this example when you put the Type after the function in the class sun of Content, the protocol Content will be this one type
Update
I am putting another example using "swiftly" syntax instead of traditional getContent.
protocol Content{
associatedtype T
var content:T { get }
}
class A: Content {
var content:String{
return "Hello World"
}
}
class B: Content {
var content:Int{
return 42
}
}
A().content //"Hello World"
B().content //42
You can use generics and meta-types:
protocol Content {
func getContent<T>(ofType: T.Type) -> T?
}
class A: Content {
func getContent<T>(ofType: T.Type) -> T? {
return "Im a String" as? T ?? nil
}
}
class B: Content {
func getContent<T>(ofType: T.Type) -> T? {
return 1234 as? T ?? nil
}
}
let aClass = A()
let aValue = aClass.getContent(ofType: String.self) // "Im a String"
let bClass = B()
let bValue = bClass.getContent(ofType: Int.self) // 1234

Can I specify that a class instance can be converted to some type?

Say I have a generic class
class Foo<T> { … }
Can I somehow specify that instances of this class can be converted to T in assignments? Example:
let foo = Foo<Int>()
func useAnInt(a: Int) {}
let getTheInt: Int = foo
useAnInt(foo)
Why not just use the underlying type? (Similar to #MrBeardsley's answer)
class Foo<T> {
var t : T
init(t: T) {
self.t = t
}
}
let foo = Foo(t: 3)
func useAnInt(a: Int) {}
let getTheInt: Int = foo.t
useAnInt(foo.t)
You are not able to do what you are asking. Even though Foo defines a generic type T, instances of Foo are still Foo and cannot be converted to the generic type. The reason you would declare a generic type at the class level is to use it multiple places throughout the class.
class Foo<T> {
var value: T
init(withValue: T) {
self.value = withValue
}
func getSomeValue() -> T {
return self.value
}
}
Generics don't mean the class itself is generic and can be converted.
One way of achieving what you want is to use a dedicated protocol for each of the target types that your class shall be convertible to. Here is very basic example:
protocol BoolAdaptable {
func adaptToBool() -> Bool
}
protocol IntAdaptable {
func adaptToInt() -> Int
}
protocol FloatAdaptable {
func adaptToFloat() -> Float
}
class Foo: BoolAdaptable, IntAdaptable, FloatAdaptable {
var v: NSNumber
init(_ v: NSNumber) {
self.v = v
}
func adaptToBool() -> Bool {
return v.boolValue
}
func adaptToInt() -> Int {
return v.integerValue
}
func adaptToFloat() -> Float {
return v.floatValue
}
}
let foo = Foo(NSNumber(double: 1.23))
let getTheBool = foo.adaptToBool() // true
let getTheInt = foo.adaptToInt() // 1
let getTheFloat = foo.adaptToFloat() // 1.23
This could easily be extended to support more complex conversions.

Find out if Any is of a unspecified Type

I want to pass a object and a Type to a method and find out of the object is of the passed in Type. I have it working for AnyObject i think. But Any can be also Strcuts, Strings, Doubles ..
My solution with AnyObject looks like this:
class AClass {
}
class BClass {
}
class TypeCheck {
var type : AnyObject.Type;
init( type: AnyObject.Type ) {
self.type = type;
}
func isOfType( object: AnyObject ) -> Bool {
return self.type === object.dynamicType.self ? true : false;
}
}
var typeCheck = TypeCheck( type: AClass.self );
var a = AClass();
var b = BClass();
println( "Object \(a) is of checked Class: \(typeCheck.isOfType(a))" );//true
println( "Object \(b) is of checked Class: \(typeCheck.isOfType(b))" );//false
As like in this example with TypeCheck.type i need to store the Type i want to check against. Is there any Solution for this? All i found were solutions with specific types or only for Objects.
You can do this more simply with generics:
import UIKit
class AClass {
}
class BClass {
}
class TypeCheck<T> {
func isOfType<U>(arg: U) -> Bool {
return arg is T
}
}
var typeCheck = TypeCheck<AClass>();
var a = AClass();
var b = BClass();
println( "Object \(a) is of checked Class: \(typeCheck.isOfType(a))" );//true
println( "Object \(b) is of checked Class: \(typeCheck.isOfType(b))" );//false