Swift 3. Cast Any to class which conforms specific protocol - swift

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.

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

Call a static func on optional type

I have a protocol, conforming class and a class with one simple function.
protocol Outputable {
static func output()
}
class Foo: Outputable {
static func output() {
print("output")
}
}
class Bar {
func eat(_ object: AnyObject?) {
if let object = object, let objectType = type(of: object) as? Outputable.Type {
objectType.output()
}
}
}
let foo = Foo()
let bar = Bar()
var fooOptional: Foo?
bar.eat(foo) // prints 'output'
bar.eat(fooOptional) // print nothing
Is there any way to pass some optional type being nil but conforming to Outputable protocol and call protocol's static functions inside eat function? Even though it's nil I am still passing a type and that's all I should need inside eat, right?
To make it more clear. I know why last line prints nothing. But is there a way to adjust eat to print that 'output' string out?
One of the way you could achieve what you're seeking is to use generics and call your method on type:
func eat<T: Outputable>(_ object: T?) {
T.output()
}
This will work for both Foo and Foo?
You can extend Optional to conform to your protocol.
protocol Outputable {
func output()
}
extension Optional: Outputable {
func output() {
switch self {
case .some(let object):
print("I have an object: \(object)")
case .none:
print("I'm nil")
}
}
}
class Foo { }
class Bar {
func eat(_ object: AnyObject?) {
if let object = object as? Outputable {
object.output()
}
}
}
var foo: Foo?
let bar = Bar()
bar.eat(foo) // prints "I'm nil"
Put a break point at
if let object = object, let objectType = type(of: object) as? Outputable.Type {
objectType.output()
}
You will realise that objectType.output() is not being called. if let succeeds in swift only if the right hand side object is not nil. Which is nil in your case.
If you rewrite your test, the logic of why it's not working becomes clearer.
class Bar {
func eat(_ object: AnyObject?) {
if let object = object {
if let objectType = type(of: object) as? Outputable.Type {
objectType.output()
} else {
print("Mismatch on type")
}
} else {
print("No object provided")
}
}
}
Shows:
output
No object provided

Generic class with generic delegate. How can I distinguish which object's delegate is executing the callback?

MyClass is a generic class which has a generic delegate.
AClass contains two iVar instances of MyClass and also implements MyClassDelegate.
Where AClass implements MyClassDelegate, how can I distinguish which object is calling into the interface? With non-generic classes, == is acceptable.
Please see the comments and error messages at the bottom of this code snippet.
protocol MyClassDelegate: class {
func myClass<T>(_ myClass: MyClass<T>, valueDidChange value: T)
}
class MyClass<T: Comparable> {
private var _value: T
var value: T {
set {
delegate?.myClass(self, valueDidChange: newValue)
}
get {
return _value
}
}
var delegate: MyClassDelegate?
init(value: T) {
_value = value
}
}
class AClass {
private var thing1 = MyClass(value: Int(10))
private var thing2 = MyClass(value: Int(100))
private var thing3 = MyClass(value: TimeInterval(10))
private var thing4 = MyClass(value: TimeInterval(100))
init() {
thing1.delegate = self
thing2.delegate = self
thing3.delegate = self
thing4.delegate = self
}
}
extension AClass: MyClassDelegate {
func myClass<T>(_ myClass: MyClass<T>, valueDidChange value: T) {
// This fails to complile
// Binary operator '==' cannot be applied to operands of type 'MyClass<T>' and 'MyClass<Int>'
if myClass == thing1 {
}
// Binary operator '==' cannot be applied to operands of type 'MyClass<T>' and 'MyClass<TimeInterval>' (aka 'MyClass<Double>')
else if myClass == thing3 {
}
}
}
Restrict the T type in your protocol method signature func myClass<T>(...) to be Comparable. Since you restricted it only in one particular extension of that protocol, the method in AClass can take any kind of T, not just Comparable ones.
I tried and tried but couldn't configure the generic delegate in a manner where I could compare callers.
I read the answer from NRitH, but couldn't get the compiler to accept the syntax. Perhaps there is a way to do this, but I went a different route with success.
I gave up on the protocol/delegate technique and ended up using a callback closure. Instead of defining a delegate in MyClass and implementing that delegate in AClass, I defined a callback closure in MyClass in implemented that in AClass like so:
class MyClass<T: Comparable>: Equatable {
var valueChanged: ((_ clazz: MyClass) -> Void)?
private var _value: T
var value: T {
set {
_value = newValue
valueChanged?(self)
}
get {
return _value
}
}
init(value: T) {
_value = value
}
static public func ==(lhs: MyClass<T>, rhs: MyClass<T>) -> Bool {
return lhs.value == rhs.value
}
}
class AClass {
fileprivate var thing1: MyClass<Int> = MyClass(value: 10)
fileprivate var thing2: MyClass<Int> = MyClass(value: 100)
fileprivate var thing3: MyClass<TimeInterval> = MyClass(value: 10)
fileprivate var thing4: MyClass<TimeInterval> = MyClass(value: 100)
init() {
thing1.valueChanged = { (thing) in
// You can compare here, but you already know which object is callling back
if thing == self.thing1 {
}
}
thing2.valueChanged = { (thing) in
print("Thing2 changed: \(thing.value)")
}
}
}

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.

How to cast generic T to conform to protocol

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