How to create an Single Class coexist with Generic in Swift - swift

I have a Single Class like this:
class Single {
static let sharedInstance: Single = Single()
...
}
But I want use Generic in this Class like this:
class Single<T: Hashable> {
static let sharedInstance: Single = Single()
var dic: [T: Any] = [:] // Here use the Generic
}
I got this result from Xcode
Static stored properties not supported in generic types
I have search this error in stackoverflow, but all the answer for this is not suit for me. Like this one(How to define static constant in a generic class in swift?)
How can I solve this?

You can declare a generic type using a static computed property as follows:
class Single<T: Hashable> {
static var sharedInstance: Single? {
if self.sharedInstance != nil {
return self.sharedInstance
} else {
return Single()
}
}
var dic: [T: Any] = [:]
}

I take it you simply want the one singleton to be able to store any hashable key in your dictionary? If so, do the following:
class Single {
static let sharedInstance: Single = Single()
var dic: [AnyHashable : Any] = [:]
}
Single.sharedInstance.dic["Grimxn"] = 1
Single.sharedInstance.dic[1] = "Grimxn"
Single.sharedInstance.dic // [1: "Grimxn", "Grimxn": 1] as required

Related

Using an overriden static property during initialization

I would like to create a class with a static property that subclasses can override, which would be used to initialize instances. So far, I've tried to accomplish this like this:
import Cocoa
class A: NSObject {
class var staticProperty: String {
return "A"
}
var property: String = A.staticProperty
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
This does not work, since B().property still returns "A". How could I change this code so that property contains the value specified by the subclass? Any help would be appreciated!
Edit
I would like to initialize property with the value of staticProperty, so this could also look like this:
var property: SomeClass = SomeClass(A.staticProperty)
But then, this initialization should still use "A" for class A, and "B" for class B.
Edit 2 (After #RakeshaShastri's comment)
For my specific use-case, I need property to be stored (so not computed) and non-lazy.
Edit 3
In short, I'm trying to build a Realm model class which has a few to-many relationships to other models. For these models (which are quite similar), I'm trying to create a superclass which contains the shared functionality, amongst which is also the inverse relationship. Therefore, I want to have a static property which contains the key in the first model to either of the other models, and then initialize a LinkingObjects property using this key name. Since Realm does not allow this to be lazy or computed, I cannot use these functionalities here.
If you inherit from NSObject why not using it ?
import Cocoa
class A: NSObject {
var property: String
public override init() {
let str = type(of: self).perform(#selector(getter: type(of: self).staticProperty))?.takeUnretainedValue() as! String
property = str
}
#objc class var staticProperty: String {
return "A"
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
You can do this with this aproach
class A {
var prop: String{
return "A"
}
}
class B: A {
override var prop: String{
return "B"
}
}
print(A().prop) // "PRINTS A"
print(B().prop) // "PRINTS B"
A.staticProperty will use static dispatch and will always point to A's class property. You need dynamic dispatch here, aka type(of: self).
However, self needs an instance to work with, thus var property: String = type(of: self.staticProperty won't compile.
However, lazy properties can work around this limitation, so you could declare property as a lazy one:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private(set) lazy var property: String = { type(of: self).staticProperty }()
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
print(B().property) // B
P.S. the private(set) part is just something I usually do, I rarely allow extrinsic factors to change my object.
Update As #MartinR has pointed out, lazy is not a choice for the OP. An alternative solution that doesn't use a lazy var is to use a "shadowing" property:
class A: NSObject {
class var staticProperty: String {
return "A"
}
private var _property: String?
var property: String {
get {
return _property ?? type(of: self).staticProperty
}
set {
_property = newValue
}
}
}
class B: A {
override class var staticProperty: String {
return "B"
}
}
let b = B()
print(b.property) // B
b.property = "B'"
print(b.property) // B'

How to make a singleton for a generic class in Swift

I need to create a singleton for a generic class in Swift, but Generic Class in Swift donĀ“t support static stored properties, then this methods aren`t valid
public final class ApiClient<T>: ApiClientFor<T> where T:EntityType {
// Method 1
class var shared: ApiClient<T> {
struct Static {
static let instance = ApiClient<T>()
}
return Static.instance
}
//Or more simple Method 2
static let instance = ApiClient<T>()
}
The fundamental problem here is that you're creating a whole family of singletons (one for each parameterized type) and each singleton needs to be stored (or referenced from) the static context. And the singletons need to be indexed by the type that they store.
I suggest creating a single, global dictionary in which to store your singletons, indexed by string descriptions of their types:
var singletons_store : [String, AnyObject]
Then in your computed shared variable you look in that store for the singleton that corresponds to a parameterized type:
class var shared : APIClient<T> {
let store_key = String(describing: T.self)
if let singleton = singletons_store[store_key] {
return singleton as! APIClient<T>
} else {
let new_singleton = APIClient<T>()
singleton_store[store_key] = new_singleton
return new_singleton
}
}

Swift Unable to access static variables in class using type(of: Instance)

I have multiple classes with the same static variable. I get the currentInstance of each class at runtime(AnyObject?). Then I am trying to access static variables by getting a class from instance using type(of: instance) method. But when trying to get the static variable it throws me an error - Value of type 'AnyObject.Type' has no member . Here is pseudo code.
public extension Reader {
open static var funcDictionary = [String: readerFuncs]() //ReaderFuncs is an enum of functions
}
public extension Library {
open static var funcDictionary = [String: libraryFuncs]()
}
public extension ReaderMenu {
open static var funcDictionary = [String: readerMenuFuncs]()
}
import Foundation
open class TestClass: NSObject {
open func executeFunction(currentInstance: AnyObject) { // I get current instance at runtime. And I have checked that I get the correct value
var count = type(of: currentInstance).functionDictionary.count // Error: Value of type 'AnyObject.Type' has no member funcDictionary
}
I would like to know how to access static variables when you only have the instance of the class available. I have used .classforCoder() too but it doesn't work. All the files have the same target membership too.
You should use generic types in your TestClass executeFunction method, but we need a common reference to all three of your classes Reader, Library and ReaderMenu. To do that, we will create a protocol that each class has to conform to.
protocol Funcable {
associatedtype FuncsEnum
static var funcDictionary: [String:FuncsEnum] { get set }
}
Now each class inherits from Funcable, they are all required to have a typealias that defines the type of enum in the funcDictionary.
class Reader: Funcable {
typealias FuncsEnum = Reader.Funcs
static var funcDictionary = [String:FuncsEnum]()
enum Funcs {
case A
case B
}
}
class Library: Funcable {
typealias FuncsEnum = Library.Funcs
static var funcDictionary = [String:FuncsEnum]()
enum Funcs {
case C
case D
}
}
class ReaderMenu: Funcable {
typealias FuncsEnum = ReaderMenu.Funcs
static var funcDictionary = [String:FuncsEnum]()
enum Funcs {
case E
case F
}
}
You can define your enums outside of the classes if you like, but I've moved them inside to make it more reusable. Anyway back at the TestClass, we can use Generic Type Token T which is a mirror of the class of the given currentInstance.
class TestClass: NSObject {
func executeFunction<T: Funcable>(currentInstance: T) {
print(T.funcDictionary.count)
}
}
To access the enums individually e.g. Reader.Funcs instead of readerFuncs
UPDATE
We can just instantiate the currentInstance on our own to make it work.
let testInstance = TestClass()
Reader.funcDictionary.updateValue(.A, forKey: "a")
testInstance.executeFunction(currentInstance: Reader()) // prints 1
Library.funcDictionary.updateValue(.C, forKey: "c")
Library.funcDictionary.updateValue(.D, forKey: "d")
testInstance.executeFunction(currentInstance: Library()) // prints 2

Is it possible to obtain a Swift type from a string?

I wonder if it's possible to obtain a Swift type dynamically. For example, say we have the following nested structs:
struct Constants {
struct BlockA {
static let kFirstConstantA = "firstConstantA"
static let kSecondConstantA = "secondConstantA"
}
struct BlockB {
static let kFirstConstantB = "firstConstantB"
static let kSecondConstantB = "secondConstantB"
}
struct BlockC {
static let kFirstConstantC = "firstConstantBC"
static let kSecondConstantC = "secondConstantC"
}
}
It's possible to get value from kSeconConstantC from a variable). Like:
let variableString = "BlockC"
let constantValue = Constants.variableString.kSecondConstantC
Something akin to NSClassFromString, maybe?
No, it's not possible yet (as a language feature, at least).
What you need is your own type registry. Even with a type registry, you wouldn't be able to get static constants unless you had a protocol for that:
var typeRegistry: [String: Any.Type] = [:]
func indexType(type: Any.Type)
{
typeRegistry[String(type)] = type
}
protocol Foo
{
static var bar: String { get set }
}
struct X: Foo
{
static var bar: String = "x-bar"
}
struct Y: Foo
{
static var bar: String = "y-bar"
}
indexType(X)
indexType(Y)
typeRegistry // ["X": X.Type, "Y": Y.Type]
(typeRegistry["X"] as! Foo.Type).bar // "x-bar"
(typeRegistry["Y"] as! Foo.Type).bar // "y-bar"
A type registry is something that registers your types using a custom Hashable type (say a String or an Int). You can then use this type registry to reference registered types using custom identifiers (a String, in this case).
Since Any.Type by itself isn't all that useful, I constructed an interface Foo through which I could access a static constant bar. Because I know that X.Type and Y.Type both conform to Foo.Type, I forced a cast and read the bar property.

What is the correct way to create preset Structs?

In Swift classes we can use a class function to create preset instances. Like the calendar example below:
let calender = NSCalendar.currentCalendar()
Which will have a similar pattern as this :
class SomeClass {
var attribute : String
init(value:String) {
attribute = value
}
class func testClass() -> SomeClass {
return SomeClass(value: "test")
}
}
let test = SomeClass.testClass()
But there are no class functions in structs obviously. Xcode recommends using static instead. This is very close to the singleton pattern.
struct SomeStruct {
var attribute : String
init(value:String) {
attribute = value
}
static var testStruct = SomeStruct(value: "test")
}
Singleton pattern
class Singleton {
static let shared = Singleton()
private init() {
}
}
So is this an ok way to init a struct with preset values since structs are value types. If it is not ok, what is the correct way?
The equivalent of class func for struct types is static func:
static func testStruct() -> SomeStruct {
return SomeStruct(value: "foo")
}
and a static property (the "singleton-pattern") works identically
with both class and struct types:
static let singleStruct = SomeStruct(value: "foo")
testStruct() creates a value on each call, whereas singleStruct
creates the value once (on the first call).
In most cases that would make no difference because structures are
value types. The static property has advantages if creating the
value is "expensive". Also, as #Lance noticed in a comment,
this pattern is used by Apple frequently, such as CGRect.zero.
However, it makes a difference if the struct has properties which
are reference types (or pointers to unmanaged memory). Here is an example:
class MyClass {
var attribute : String
init(value : String) {
attribute = value
}
}
struct SomeStruct {
var ptr : MyClass
init(value : String) {
ptr = MyClass(value: value)
}
static func testStruct() -> SomeStruct {
return SomeStruct(value: "foo")
}
static let singleStruct = SomeStruct(value: "foo")
}
Using the static function:
let test1 = SomeStruct.testStruct()
print(test1.ptr.attribute) // foo
let test2 = SomeStruct.testStruct()
test2.ptr.attribute = "bar"
print(test1.ptr.attribute) // foo
Here test1 and test2 are separate values and we get the expected
output.
Using the static property:
let test1 = SomeStruct.singleStruct
print(test1.ptr.attribute) // foo
let test2 = SomeStruct.singleStruct
test2.ptr.attribute = "bar"
print(test1.ptr.attribute) // bar <--- What?
Here, test1 and test2 are set to the same value returned from
the static property. Changing test2.ptr does not mutate test2,
resulting in the somewhat unexpected output for test1.ptr.attribute
See Friday Q&A 2015-04-17: Let's Build Swift.Array for an interesting article on how this can be solved.
Btw, static can be used with class types as well, here static
is a shortcut for class final: a type method that cannot be overridden
in a subclass. Since there is no inheritance for struct types it makes
sense that type methods for struct types are written as static.