How to cast generic T to conform to protocol - swift

I need to cast the generic type in a class to conform to a protocol. I can not use constraints since the container class has to be serialized. So how could i cast in this case the T to ZNumeric when i allready know (i can check as you see) that it conforms to the protocol?
//: Playground - noun: a place where people can play
import UIKit
protocol ZNumeric {
}
extension Double: ZNumeric {
}
class GenericClass<T> {
}
class RestrictedGenericClass<T:ZNumeric> {
}
class Container {
required init?<T>(type: T.Type) {
let a = GenericClass<T>()
print(a)
if T.self is ZNumeric.Type {
print("is numeric")
//let b = RestrictedGenericClass<T>() // Will not work obviously
//print(b)
}
}
}
let cDouble = Container(type: Double.self) // if T.self is ZNumeric.Type is true
let cString = Container(type: String.self) // if T.self is ZNumeric.Type is false

Because generics have to be known at compile-time, you cannot just check at run-time for conformance (I'm pretty sure). I think this is more like what you want:
class Container {
required init?<T>(type: T.Type) {
let a = GenericClass<T>()
print(a)
}
required init?<T : ZNumeric>(type: T.Type) {
let a = GenericClass<T>()
print(a)
print("is numeric")
let b = RestrictedGenericClass<T>()
print(b)
}
}
The more specific initialiser will be chosen at compile-time.

I think you looking for this.
protocol ZNumeric {
}
extension Double: ZNumeric {
}
class GenericClass<T> {
}
class RestrictedGenericClass<T:ZNumeric> {
}
class Container<T> {
required init?(value: T) {
}
convenience init?(_ value: T) {
self.init(value: value)
let a = GenericClass<T>()
print(a)
}
}
extension Container where T: ZNumeric {
convenience init?(_ value: T) {
self.init(value: value)
let b = RestrictedGenericClass<T>() // Will not work obviously
print(b)
}
}
print("test Double")
let cDouble = Container(1.1) // if T.self is ZNumeric.Type is true
print("test String")
let cString = Container("") // if T.self is ZNumeric.Type is false
// test Double
// RestrictedGenericClass<Swift.Double>
// test String
// GenericClass<Swift.String>
make internal Required Initializer
make initializer for T: AnyObject
make initializer for T: ZNumeric

Related

Get different class types by `var` from inherited objects

I need to get different class types by var from inherited objects. and I need these objects to be not generic. something like this
import Foundation
protocol MyClassProtocol {
associatedtype MyClass: Any
var myClass: MyClass.Type { get }
}
extension MyClassProtocol {
var myClass: MyClass.Type {
get { Self.MyClass.self }
}
}
class A: MyClassProtocol {
typealias MyClass = String
}
class B: A {
typealias MyClass = Int64
}
let a = A().myClass // String.Type
let a1 = A.MyClass.self // String.Type
let b = B().myClass // String.Type
let b1 = B.MyClass.self // Int64.Type
let list: [A] = [A(),B()]
// any way, how i get from this list different classes?
let la = list[0].myClass // String.Type
let la1 = type(of: list[0]).MyClass.self // String.Type
let lb = list[1].myClass // String.Type
let lb1 = type(of: list[1]).MyClass.self // String.Type
how I can resolve it? I cant use generic because I have array: [A]
If you want to achieve this kind of functionality, you will have store the class type as an instance variable and utilize class types that conform to AnyClass aka AnyObject.Type like below.
There is no practical reason to do this, and it is highly discouraged, but if you want to call something like classB.staticMethod() this is how you would do it.
class MyCustomClass: NSObject {
#objc
static func myStaticMethod() { print("why the heck do i need this?") }
}
protocol MyClassProtocol {
var myClass: AnyClass { get }
}
class A: MyClassProtocol {
var myClass: AnyClass { return NSString.self }
}
class B: A {
override var myClass: AnyClass { return MyCustomClass.self }
}
var list: [MyClassProtocol] = [A(), B()]
let classA: AnyClass = list[0].myClass.self // NSString
let classB: AnyClass = list[1].myClass.self // MyCustomClass
if classB.responds(to: #selector(MyCustomClass.myStaticMethod)) {
classB.performSelector(inBackground: #selector(MyCustomClass.myStaticMethod),
with: nil)
}

Using swift Generic Types with protocols

I've tried to use generic type with protocol:
class Weak<T: AnyObject> {
weak var value: AnyObject?
init (value: AnyObject) {
self.value = value
}
}
protocol SomeProtocol: AnyObject {
func doSomething()
}
func createWeak(object: SomeProtocol) -> Weak<SomeProtocol> {
return Weak<SomeProtocol>(value: object)
}
class SomeClass: SomeProtocol {
func doSomething() {
print("Some 2")
}
}
let temp = SomeClass()
let weakObject = createWeak(object: temp)
weakObject.value?.doSomething()
And got the compiler error:
error: 'SomeProtocol' is not convertible to 'AnyObject'
return Weak(value: object)
But without AnyObject constraint it works fine
class Weak<T> {
var value: T?
init (value: T) {
self.value = value
}
}
protocol Protocol {
func doSomething()
}
class Class: Protocol {
func doSomething() {
print("This is class")
}
}
func createWeak(object: Protocol) -> Weak<Protocol> {
return Weak(value: object)
}
let temp = Class()
let weakObject = createWeak(object: temp)
weakObject.value?.doSomething()
Why I can't use protocols inherited form AnyObject in generic classes?
Swift protocols are incomplete types, which means that you can't use them in places like generic arguments, as the compiler needs to know the whole type details so it can allocate the proper memory layout.
Your createWeak function can still be used if you make it generic:
func createWeak<T: SomeProtocol>(object: T) -> Weak<T> {
return Weak<T>(value: object)
}
The above code works because the compiler will generate at compile time a function mapped to the concrete type you pass.
Even better, you can make the initializer generic, and convert Weak to a struct (value types are preferred Swift over reference ones):
struct Weak<T: AnyObject> {
weak var value: T?
init(_ value: T) {
self.value = value
}
}
which you can use it instead of the free function:
let weakRef = Weak(temp)

Swift 3. Cast Any to class which conforms specific protocol

I have a random protocol as example
protocol testP {
init(param1: String)
}
And I have a class, which take Any as parameter as example:
class testC {
var aClass: Any
}
How can I check if aClass conforms to protocol testP and if it does, create a new object using protocol initializer, as example:
let newObject = aClass(param1: "Hello World!")
Please, help
You can test it as other type checking with if-let:
protocol TestP {
init(param1: String)
}
class TestC {
var aClass: Any
init(_ aClass: Any) {
self.aClass = aClass
}
}
class MyClassA: TestP {
required init(param1: String) {
//
}
}
class MyClassB {
}
let containerA = TestC(MyClassA.self)
let containerB = TestC(MyClassB.self)
if let testPType = containerA.aClass as? TestP.Type {
var a = testPType.init(param1: "abc")
print(a) //->MyClassA
}
if let testPType = containerB.aClass as? TestP.Type {
print("This print statement is not executed")
}
By the way, if you assign only class types to aClass, consider using AnyClass or Any.Type.

swift 3 downcast to dynamic class

I am trying to create a couple of objects which are dependent one to each other and they mush have a method to downcast directly the concrete class of the other object. Something like this:
protocol aProt
{
var bVar:bProt! { get set }
}
protocol bProt
{
var aVar:aProt! { get set }
}
class a: aProt
{
var bVar: bProt!
func bConcrete() -> b {
return bVar as! b
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete() -> a {
return aVar as! a
}
Now, the problem is that I want this behavior (func aConcrete(),func bConcrete()) to be inherited by the subclasses of a and b. Then I thought the perfect way of doing this was using generics, but... There's no way of doing this.
class a: aProt
{
var bVar: bProt!
func bConcrete() -> T {
return bVar as! T
}
}
class b: bProt
{
var aVar: aProt!
func aConcrete<T>() -> T {
return aVar as! T
}
You can do it but when you have to use it you must downcast the variable anyway, so there is no way of doing it in a clean manner:
let aObject = a()
let bSubclassObject = a.bConcrete() // The compiler complains it cannot infer the class of T
let bSubclassObject = a.bConcrete() as! bSubclass // this works, but this is exactly which I wanted to avoid... :(
Define the generic function and add where to T:
protocol aProt {
var bVar: bProt! { get set }
}
protocol bProt {
var aVar:aProt! { get set }
}
class a: aProt {
var bVar: bProt!
func bConcrete<T: b>(_ type: T.Type) -> T? {
return bVar as? T
}
}
class b: bProt {
var aVar: aProt!
func aConcrete<T: a>(_ type: T.Type) -> T? {
return aVar as? T
}
}
class a1: a { }
class b1: b {
var fullName: String = "new object"
}
let aObj = a()
aObj.bVar = b1()
let bObj = aObj.bConcrete(b1.self)
bObj?.fullName
According to your requirement, calls bConcrete(b1.self) might still not good enough, but at least you need to know what type of data you are expecting to return.

Unwrapping generic type

Let's say I have some variable with type
let someVariable: SomeType<AnotherType?>
and I am sure that this concrete instance not contain any nil of AnotherType?. Is there is general way to convert it to SomeType<AnotherType>? For example, I need this convert for use someVariable in some function.
It could go along these lines:
protocol _Optional {
associatedtype _Wrapped
func unveil() -> _Wrapped?
}
extension Optional: _Optional {
typealias _Wrapped = Wrapped
func unveil() -> _Wrapped? { return self }
}
extension SomeType where T: _Optional {
func rewrap() -> SomeType<T._Wrapped>? {
guard let _value = value.unveil() else { return nil }
return SomeType<T._Wrapped>(value: _value)
}
}
struct SomeType<T> {
let value: T
}
let someValue = SomeType<Int?>(value: 42) // SomeType<Int?>
let rewrappedValue = someValue.rewrap() // SomeType<Int>?
let forceUnwrappedValue = someValue.rewrap()! // SomeType<Int>
Specifics depend on details of the particular implementation for SomeType (I use a simplest assumption in my example).