Properties with generic type - ios

Is it possible to have properties with generic type?
What I am trying to do:
Have a base class called Value with the following structure:
class Value {
var genericProperty: T
init<T>(type: T) {
switch type.self {
case is Int.Type:
genericProperty is Int
case is [Int.Type]:
genericProperty is [Int]
default:
genericProperty is Any
}
}
}
Then have a bunch of subclasses that define what the type of genericProperty should be.
Something like this:
class IntValue: Value {
override init<T>(type: T) {
super.init(type: Int.self)
}
}
class IntArrayValue: Value {
override init<T>(type: T) {
super.init(type: [Int.self])
}
}
Is this somehow possible with associatedType or any of the sorts?
For clarification (possibly this design is bad). I would like to do something along this line:
func handle(values: [Value]) {
values.forEach {
switch $0 {
case is IntValue.Type:
// Here I will now know that `genericProperty` will have type `Int`
// and can assign to a property with `Int` type
property: Int = $0.genericProperty
case is IntArrayValue.Type:
// Here I know it will be an array
...
}
}
}

Not sure if that's what you are looking for, but... you can create a generic base class and add subclasses which specify the concrete type:
class Value<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
Now some subclasses with specific value type:
class IntValue: Value<Int> {}
class StringValue: Value<String> {}
And here's how to use them:
let intValue = IntValue(42)
intValue.value // 42
let stringValue = StringValue("Hi")
stringValue.value // "Hi"

In general the answer is no.
In your example, genericProperty would have a different type in the subclass to the superclass and that would break the type system. If you could do it, you could then legitmiately try something like this:
var array: [Value] = []
array.append(IntValue())
array.append(FloatValue())
for v in array
{
let foo = v.genericProperty
}
What should the compiler infer for the type of foo?

Related

Testing type for class conformance in Swift

EDIT: The previous answers alluded to in the comments don't answer the question, which was how to determine if any given Type was a reference type and how to safely conform said type to AnyObject.
Testing against the passed type doesn't work, as the underlying type could be optional, or it could be a protocol, in which case one needs to know the passed instance is a class type or value type.
The solution I came up with is similar to the revised answer provided below.
So I have a new dependency injection framework, Factory.
Factory allows for scoped instances, basically allowing you to cache services once they're created. And one of those scopes is shared. Any instance shared will be cached and returned just as long as someone in the outside world maintains a strong reference to it. After the last reference releases the object the cache releases the object and a new instance will be created on the next resolution.
This is implemented, obviously, as simply maintaining a weak reference to the created object. If the weak reference is nil it's time to create a new object.
And therein lies the problem
Weak references can only apply to reference types.
Factory uses generics internally to manage type information. But I can create Factories of any type: Classes, structs, strings, whatever.)
Scopes use dictionaries of boxed types internally. If an instance exists in the cache and in the box it's returned. So what I'd like to do is create this...
private struct WeakBox<T:AnyObject>: AnyBox {
weak var boxed: T
}
The AnyObject conformance is need in order to allow weak. You get a compiler error otherwise. Now I want to box and cache an object in my shared scope with something like this...
func cache<T>(id: Int, instance: T) {
cache[id] = WeakBox(boxed: instance)
}
But this also gives a compiler error. (Generic struct WeakBox requires T to be a class type.)
So how to bridge from on to the other? Doing the following doesn't work. Swift shows a warning that "Conditional cast from 'T' to 'AnyObject' always succeeds" and then converts the type anyway.
func cache<T>(id: Int, instance: T) {
if let instance = instance as? AnyObject {
cache[id] = WeakBox(boxed: instance)
}
}
I'd be happy with the following, but again, same problem. You can't test for class conformance and you can't conditionally cast to AnyObject. Again, it always succeeds.
private struct WeakBox: AnyBox {
weak var boxed: AnyObject?
}
func cache<T>(id: Int, instance: T) {
if let instance = instance as? AnyObject {
cache[id] = WeakBox(boxed: instance)
}
}
What I'm doing at the moment is something like...
private struct WeakBox: AnyBox {
weak var boxed: AnyObject?
}
func cache<T>(id: Int, instance: T) {
cache[id] = WeakBox(boxed: instance as AnyObject)
}
Which works, but that instance as AnyObject cast depends on some very weird Swift to Objective-C bridging behavior.
Not being able to test for class conformance at runtime is driving me bonkers, and seems like a semi-major loophole in the language.
You can't test for conformance, and you can't cast for conformance.
So what can you do?
As Martin notes in a comment, any value can be cast to AnyObject in Swift, because Swift will wrap value types in an opaque _SwiftValue class, and the cast will always succeed. There is a way around this, though.
The way to check whether a value is a reference type without this implicit casting is to check whether its type is AnyObject.Type, like so:
func printIsObject(_ value: Any) {
if type(of: value) is AnyObject.Type {
print("Object")
} else {
print("Other")
}
}
class Foo {}
struct Bar {}
enum Quux { case q }
printIsObject(Foo()) // => Object
printIsObject(Bar()) // => Other
printIsObject(Quux.q) // => Other
Note that it's crucial that you check whether the type is AnyObject.Type not is AnyObject. T.self, the object representing the type of the value, is itself an object, so is AnyObject will always succeed. Instead, is AnyObject.Type asks "does this inherit from the metatype of all objects", i.e., "does this object which represents a type inherit from an object that represents all object types?"
Edit: Evidently, I'd forgotten that Swift includes AnyClass as a synonym for AnyObject.Type, so the check can be simplified to be is AnyClass. However, leaving the above as a marginally-expanded explanation for how this works.
If you want this method to also be able to handle Optional values, you're going to have to do a bit of special-casing to add support. Specifically, because Optional<T> is an enum regardless of the type of T, you're going to need to reach in to figure out what T is.
There are a few ways to do this, but because Optional is a generic type, and it's not possible to ask "is this value an Optional<T>?" without knowing what T is up-front, one of the easier and more robust ways to do this is to introduce a protocol which Optional adopts that erases the type of the underlying value while still giving you access to it:
protocol OptionalProto {
var wrappedValue: Any? { get }
}
extension Optional: OptionalProto {
var wrappedValue: Any? {
switch self {
case .none: return nil
case let .some(value):
// Recursively reach in to grab nested optionals as needed.
if let innerOptional = value as? OptionalProto {
return innerOptional.wrappedValue
} else {
return value
}
}
}
}
We can then use this protocol to our advantage in cache:
func cache(id: Int, instance: Any) {
if let opt = instance as? OptionalProto {
if let wrappedValue = opt.wrappedValue {
cache(id: id, instance: wrappedValue)
}
return
}
// In production:
// cache[id] = WeakBox(boxed: instance as AnyObject)
if type(of: instance) is AnyClass {
print("\(type(of: instance)) is AnyClass")
} else {
print("\(type(of: instance)) is something else")
}
}
This approach handles all of the previous cases, but also infinitely-deeply-nested Optionals, and protocol types inside of Optionals:
class Foo {}
struct Bar {}
enum Quux { case q }
cache(id: 1, instance: Foo()) // => Foo is AnyClass
cache(id: 2, instance: Bar()) // => Bar is something else
cache(id: 3, instance: Quux.q) // => Quux is something else
let f: Optional<Foo> = Foo()
cache(id: 4, instance: f) // => Foo is AnyClass
protocol SomeProto {}
extension Foo: SomeProto {}
let p: Optional<SomeProto> = Foo()
cache(id: 5, instance: p) // => Foo is AnyClass
So this took a while to figure out and even longer to track down the clues needed for a solution, so I'm providing my own code and answer to the problem
Given the following protocol...
private protocol OptionalProtocol {
var hasWrappedValue: Bool { get }
var wrappedValue: Any? { get }
}
extension Optional : OptionalProtocol {
var hasWrappedValue: Bool {
switch self {
case .none:
return false
case .some:
return true
}
}
var wrappedValue: Any? {
switch self {
case .none:
return nil
case .some(let value):
return value
}
}
}
And a box type to hold a weak reference...
private protocol AnyBox {
var instance: Any { get }
}
private struct WeakBox: AnyBox {
weak var boxed: AnyObject?
var instance: Any {
boxed as Any
}
}
Then the code to test and box a give type looks like...
func box<T>(_ instance: T) -> AnyBox? {
if let optional = instance as? OptionalProtocol {
if let unwrapped = optional.wrappedValue, type(of: unwrapped) is AnyObject.Type {
return WeakBox(boxed: unwrapped as AnyObject)
}
} else if type(of: instance) is AnyObject.Type {
return WeakBox(boxed: instance as AnyObject)
}
return nil
}
Note that the type passed in could be a class, or a struct or some other value, or it could be a protocol. And it could be an optional version of any of those things.
As such, if it's optional we need to unwrap it and test the actual wrapped type to see if it's a class. If it is, then it's safe to perform our AnyObject cast.
If the passed value isn't optional, then we still need to check to see if it's a class.
There's also a StrongBox type used for non-shared type caching.
struct StrongBox<T>: AnyBox {
let boxed: T
var instance: Any {
boxed as Any
}
}
And the final cache routine looks like this.
func resolve<T>(id: UUID, factory: () -> T) -> T {
defer { lock.unlock() }
lock.lock()
if let box = cache[id], let instance = box.instance as? T {
if let optional = instance as? OptionalProtocol {
if optional.hasWrappedValue {
return instance
}
} else {
return instance
}
}
let instance: T = factory()
if let box = box(instance) {
cache[id] = box
}
return instance
}
Source for the entire project is in the Factory repository.

How I can get rawValue from enum, if element is Any?

I have a variable of type Any?. I'm totally know what that variable is type of enum: String. How I can get rawValue something like:
var somevar: Any? = someValue
(somevar as ?????).rawValue
First of all sorry I misunderstood your question.
Yes it is possible and very EASY
it is beauty of swift
You have to add some extra step there
Step1 :
Add protocol
protocol TestMe {
var rawValueDesc: String {get}
}
Step 2 :
In your enum implement it
enum YourEnum:String,TestMe {
case one = "test"
case two = "test1"
var rawValueDesc: String {
return self.rawValue
}
}
Finally
var testdd:Any = YourEnum.one
if let finalValue = testdd as? TestMe {
print( finalValue.rawValueDesc)
}
Hope it is helpful to you
Assuming you have this defined somewhere in your or in imported module:
enum First: String {
case a, b
}
enum Second: String {
case c, d
}
In you module your should do something like this:
protocol StringRawRepresentable {
var rawValue: String { get }
}
extension First: StringRawRepresentable {}
extension Second: StringRawRepresentable {}
And here's your problem:
var somevar: Any? = someValue
let result = (somevar as? StringRawRepresentable)?.rawValue
If, for example, someValue == Second.c you gonna get "c" in result.
This approach will work, but you will have to extend all the possible types, otherwise as? casting will result in nil even if type has rawValue: String property.

Swift Generic Unknown Member with Protocol Extension

If I have the following code:
protocol ObjectType {
var title: String { get set }
}
extension ObjectType {
var objectTypeString: String {
let mirror = Mirror(reflecting: self)
return "\(mirror.subjectType)"
}
}
class Object: ObjectType {
var title = ""
}
class SomeOtherClass {
private func someFunc<T: Object>(object: T) {
print(object.objectTypeString)
}
}
where Object conforms to ObjectType, you would expect that you can access objectTypeString on any ObjectInstance. But the compiler says that Type T has no member objectTypeString when that member is accessed on some generic type that inherits from Object, as shown in the code above. When the function is non-generic and just passes in an Object parameter, there's no issue. So why does have the parameter be generic make it so I can't access a member of the protocol that the conforming class should have access to?
I came across this question here but I'm not interested in workarounds, I'd just like to understand what it is about the generic system that makes my example not work. (Simple workaround is to do <T: ObjectType>)
Maybe I'm wrong or i didn't understand your question completely, but i think you might be missing initiating "object".
your willing code maybe the code below:
protocol ObjectType {
var title: String { get set }
}
extension ObjectType {
var objectTypeString: String {
let mirror = Mirror(reflecting: self)
return "\(mirror.subjectType)"
}
}
class Object: ObjectType {
var title = ""
}
class SomeOtherClass {
private func someFunc<T: Object>(object: T) {
let object = Object()
print(object.objectTypeString)
}
}
but the thing is, even if we dont initiate the object, the auto complete brings the objectTypeString up! that's what i don't understand, and as you said maybe its where the bug happens!
hope it helps <3

Swift: how to return class type from function

I know it is possible to pass class type to a function in swift:
func setGeneric<T>(type: T.Type){ }
setGeneric(Int.self)
But how we can return type from function? Writing something like
func getGeneric<T>() -> T.Type {
return Int.self
}
gives compiler error "Int is not identical to T". So is it possible to return type from a swift function?
Edit
Some explanation. I have classes that are used for persistence (I'm using Realm) and I have classes that acts as wrappers around this classes. All wrappers inherits from RealmClassWrapper which needs to know what Realm class it actually wraps. So lets say I have this realm model:
class RealmTodo: RLMObject {
dynamic var title = ""
}
and my wrappers supper class looks like this:
class RealmClassWrapper {
private let backingModel: RLMObject
//...
func backingModelType<T>() -> T.Type{ fatalError("must be implemented") }
}
and actual wrapper:
class Todo: RealmClassWrapper {
//some other properties
func backingModelType<T>() -> T.Type{ return RealmTodo.self }
}
You can return any type you want.
func getTypeOfInt() -> Int.Type { return Int.self }
func getTypeOfBool() -> Bool.Type { return Bool.self }
If the type is not determined from arguments or if the return is constant, there is no need to introduce a generic T type.
It works when I modify your function like this:
func getGeneric<T>(object: T) -> T.Type {
return T.self
}
getGeneric(0) // Swift.Int
You can force the downcast (as!) as below
func getGeneric<T>() -> T.Type {
return Int.self as! T.Type
}
But out of the function scope, you need to indicate the returned type:
var t:Int.Type = getGeneric()
Yes, this is possible. The problem here is that you say your function returns a generic T.type, but you always return Int.type. Since T is not always an Int, the compiler raises an error.
If you don't want to specify the return type you can use AnyClass as it instead of a template parameter.
class A {}
class B {}
public enum ExampleEnum: String {
case a
case b
func asClass() -> AnyClass {
switch self {
case .a:
return A.self
case .b:
return B.self
}
}
}
let myGoal : AnyClass = ExampleEnum.a.asClass()
You can also avoid the final cast to AnyClass, but compiler will show you an error

Cannot assign to property in protocol - Swift compiler error

I'm banging my head against the wall with the following code in Swift. I've defined a simple protocol:
protocol Nameable {
var name : String { get set }
}
and implemented that with:
class NameableImpl : Nameable {
var name : String = ""
}
and then I have the following method in another file (don't ask me why):
func nameNameable( nameable: Nameable, name: String ) {
nameable.name = name
}
The problem is that the compiler gives the following error for the property assignment in this method:
cannot assign to 'name' in 'nameable'
I can't see what I'm doing wrong... The following code compiles fine:
var nameable : Nameable = NameableImpl()
nameable.name = "John"
I'm sure it's something simple I've overlooked - what am I doing wrong?
#matt's anwer is correct.
Another solution is to declare Nameable as a class only protocol.
protocol Nameable: class {
// ^^^^^^^
var name : String { get set }
}
I think, this solution is more suitable for this case. Because nameNameable is useless unless nameable is a instance of class.
It's because, Nameable being a protocol, Swift doesn't know what kind (flavor) of object your function's incoming Nameable is. It might be a class instance, sure - but it might be a struct instance. And you can't assign to a property of a constant struct, as the following example demonstrates:
struct NameableStruct : Nameable {
var name : String = ""
}
let ns = NameableStruct(name:"one")
ns.name = "two" // can't assign
Well, by default, an incoming function parameter is a constant - it is exactly as if you had said let in your function declaration before you said nameable.
The solution is to make this parameter not be a constant:
func nameNameable(var nameable: Nameable, name: String ) {
^^^
NOTE Later versions of Swift have abolished the var function parameter notation, so you'd accomplish the same thing by assigning the constant to a variable:
protocol Nameable {
var name : String { get set }
}
func nameNameable(nameable: Nameable, name: String) {
var nameable = nameable // can't compile without this line
nameable.name = name
}
Here, i written some code, that might give some idea on Associated generic type Usage:
protocol NumaricType
{
typealias elementType
func plus(lhs : elementType, _ rhs : elementType) -> elementType
func minus(lhs : elementType, _ rhs : elementType) -> elementType
}
struct Arthamatic :NumaricType {
func addMethod(element1 :Int, element2 :Int) -> Int {
return plus(element1, element2)
}
func minusMethod(ele1 :Int, ele2 :Int) -> Int {
return minus(ele1, ele2)
}
typealias elementType = Int
func plus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs + rhs
}
func minus(lhs: elementType, _ rhs: elementType) -> elementType {
return lhs - rhs
}
}
**Output:**
let obj = Arthamatic().addMethod(34, element2: 45) // 79

Resources