Why not use a struct-based singleton in Swift - swift

Why not use a struct-based singleton?
I created decodable struct-based singleton.
struct Person: Decodable {
static var shared = Person()
private(set) var name: String?
var age: Int?
private init() {
}
mutating func initData(from data: Data) {
if let person = try? JSONDecoder().decode(Person.self, from: data) {
self = person
}
}
}
init from other class like this:
Person.shared.initData(from: data)
and use parameters:
let name = Person.shared.name
Person.shared.name = "MyName" //error
Person.shared.age = 20
Is this the wrong way?

You can't use a struct fora singleton because struct is a value type so when you assign it to a variable you get a copy. This can be easily shown
struct Singleton {
static var shared = Singleton()
var value: Int
private init() {
value = 0
}
}
Singleton.shared.value = 1
var otherSingleton = Singleton.shared
otherSingleton.value = 2
Now if we print the value of both
print(Singleton.shared.value, otherSingleton.value)
we get
1 2
So otherSingleton is clearly a separate instance so now we have 2 singletons :)
But if we simply change the type of Singleton to class that is a reference type and then run the same code the result of the print is
2 2
since it is the same instance we have changed the value property for.

Related

Generating auto-incrementing Instance IDs in Swift using Protocols and protocol-extensions only

Goal
To create an "AutoIDable" protocol with the following behaviour.
Every instance of a class conforming to this protocol will get an auto-generated "id" property of String type.
The code should generate id strings in the format <prefix><Instance-count-starting-from-1> (Eg: E-1, E-2, ...E-<n> and so on for 1st , 2nd ... nth Instance of the conforming class.
The protocol & protocol extensions should do ALL of the required work to generate the id strings. The conforming class will only have to subscribe to the protocol and nothing more.
Current status:
I have achieved Goal-1 & Goal-2 with the following implementation:
protocol Identifiable {
var id: String { get }
}
protocol AutoIDable: Identifiable{
static var _instanceCount: Int { get set }
}
class AutoID: AutoIDable {
init(idPrefix: String) {
setAutoID(prefix: idPrefix)
}
internal static var _instanceCount: Int = 0
var id: String = ""
func setAutoID(prefix: String = ""){
Self._instanceCount += 1
self.id = "\(prefix)\(Self._instanceCount)"
}
}
class Employee: AutoID {
init(){
super.init(idPrefix: "E-")
}
}
let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id)
print(e2.id)
print(e3.id)
print(e1.id)
The output from running the above code:
E-1
E-2
E-3
E-1
Todo:
To achieve Goal-3, I need to eliminate the AutoID superclass and implement the same functionality using protocol extensions.
I ran into trouble because:
Protocol extensions do not allow static stored properties. I do know how to work around this limitation without using a superclass.
I do not know how to inject code into all the initialisers the creator of the Employee class might create. Again, I could not think of a workaround without using a superclass.
I would be grateful if you can point me in the right direction.
PS: New to Swift programming. If you’ve suggestions for implementing the code in a more “swifty” way, please do let me know. :-)
Since you want to use protocols, you can't have a stored property in the protocol. So, you'll need some place to store the incrementing ID value, if not the IDs themselves.
Not sure if it violates your requirements of using only protocols, because it would require a type for storage, but at least it won't require conforming classes to have a superclass.
So, let's say we build such a class that holds all the IDs and keeps the incrementing counter:
class AutoIncrementId {
static private var inc: Int = 0
static private var ids: [ObjectIdentifier: String] = [:]
static func getId(_ objectId: ObjectIdentifier, prefix: String) -> String {
if let id = ids[objectId] { return id }
else {
inc += 1
let id = "\(prefix)\(inc)"
ids[objectId] = id
return id
}
}
}
Then the protocol requirement could be:
protocol AutoIdentifiable {
static var prefix: String { get }
var id: String { get }
}
So, a class would need to define its prefix. But we could define a default implementation for id:
extension AutoIdentifiable where Self: AnyObject {
var id: String {
AutoIncrementId.getId(ObjectIdentifier(self), prefix: Self.prefix)
}
}
The usage would be:
class Employee: AutoIdentifiable {
static let prefix = "E-"
}
let e1 = Employee()
let e2 = Employee()
let e3 = Employee()
print(e1.id) // E-1
print(e2.id) // E-2
print(e3.id) // E-3
print(e1.id) // E-1

Swift property wrappers. Assign by reference

I would like to share a string between classes, and keep modifications made on that string synchronised.
I thought of doing a property wrapper like:
#propertyWrapper class StringHolder {
var wrappedValue: String?
init(wrappedValue: String?) {
self.wrappedValue = wrappedValue
}
}
and then use it:
#StringHolder var sharedString: String = "testString"
let anotherClass = AnotherClass()
anotherClass.sharedString = sharedString
anotherClass.sharedString = "modified"
//sharedString is still "testString"
The problem is that when assigning the sharedString, only the wrapped value is re-set.
Is it possible to have the same wrapper assigned by reference to two properties?

How to create an Single Class coexist with Generic in 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

Listing all class attributes swift 3

I'm trying to print all the values from an object that inherits from a class, here is my example:
I create the class:
class Pokemon {
var name: String?
var type: String?
var level: Int?
var exp = 0.0
}
Create the object and assign some values:
var pikachu = Pokemon()
pikachu.name = "Pika Pika"
pikachu.level = 1
pikachu.type = "electricity"
pikachu.exp = 0
Now I would like to loop through all the pikachu object attributes and print the values. I'm thinking in a for each loop but I'm not sure how to implement it.
I know I can do something like this:
func printStats(pokemon: Pokemon) {
if pokemon.name != nil {
print(" name: \(pokemon.name!)\n level:\(pokemon.level!)\n type:\(pokemon.type!)\n exp: \(pokemon.exp!)")
}
}
printStats(pokemon: pikachu)
output:
name: Pika Pika
level:1
type:electricity
exp: 0.0
But I just want to loop through all values, instead of explicit writing every attribute in the function.
I found it the way of doing it:
let pokeMirror = Mirror(reflecting: pikachu)
let properties = pokeMirror.children
for property in properties {
print("\(property.label!) = \(property.value)")
}
output:
name = Optional("Pika Pika")
type = Optional("electricity")
level = Optional(1)
exp = Optional(0.0)
and if you want to remove the "Optional" just initialize the attributes.
Looks like a duplicate of Does Swift support reflection?
Alternatively, you can use a dictionary to store the attributes of Any? type.
e.g.
class Pokemon {
var attributes = [String:Any?]()
}
var pikachu = Pokemon()
pikachu.attributes["name"] = "Pika Pika"
pikachu.attributes["level"] = 1
pikachu.attributes["type"] = "electricity"
pikachu.attributes["exp"] = 0
func printStats(pokemon: Pokemon) {
pokemon.attributes.forEach { key, value in
if let value = value {
print("\(key): \(value)")
}
}
}
In Swift 5 you can create a new func in your class:
func debugLog() {
print(Mirror(reflecting: self).children.compactMap { "\($0.label ?? "Unknown Label"): \($0.value)" }.joined(separator: "\n"))
}
And then call it with MyObject().debugLog()
use Mirror API to get instance's properties
if you are developing iOS app, using NSObject, you may want to override description. Then can use print to print the instance.
A mirror describes the parts that make up a particular instance, such as the instance’s stored properties, collection or tuple elements, or its active enumeration case.
class YourClass: NSObject {
public override var description: String {
var des: String = "\(type(of: self)) :"
for child in Mirror(reflecting: self).children {
if let propName = child.label {
des += "\(propName): \(child.value) \n"
}
}
return des
}
}
let instance = YourClass()
print(instance)
see more in Reflection in Swift

Cannot use mutating member on immutable value of type

I have following struct:
public protocol SuperModel {
// empty protocol
}
struct ModelOne: SuperModel {
struct SubModelOne {
var someVar: Double
var othervar: Double?
}
var sub: SubModelOne?
mutating func setSub(sub: SubModelOne) {
self.sub = sub
}
}
In my class, I want to use this struct like that:
final class SomeClass: SuperClass {
var data: SuperModel
init() {
self.data = ModelOne()
}
func someFunc() {
(self.data as! ModelOne).setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
}
}
I get following error: Cannot use mutating member on immutable value of type 'ModelOne'. Why is that so and how can I fix this?
When you apply type casting to value types (such structs), if succeed, you receive immutable copy of requested value:
(self.data as! ModelOne) // this is copy of data
The only way (as known to me) how you can mutate values that need to be casted - reassign value (as #Sahil Beri pointed you need declare variable):
func someFunc() {
if var data = data as? ModelOne {
data.setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
self.data = data // you can do this since ModelOne conforms to SuperModel
}
}
Use like this,
struct UserAttributes {
var name:String?
var organizationID:String?
var email:String?
mutating func parseUserAttributes(attribues:[AWSCognitoIdentityProviderAttributeType])->UserAttributes{
for type in attribues{
if type.name == "name"{
name = type.value
}else if(type.name == "family_name"){
organizationID = type.value
}else if(type.name == "custom:role_id"){
role = type.value
}else if(type.name == "email"){
email = type.value
}
}
}
}
In some other file call like this,
var userAttributes = UserAttributes()
userAttributes = userAttributes.parseUserAttributes(attribues:attributes)
Problem is that you have declared data as SuperModel but allocate it as ModelOne. Declare data as ModelOne. Then the problem goes away.
final class SomeClass: SuperClass {
var data: ModelOne
init() {
self.data = ModelOne()
}
func someFunc() {
(self.data).setSub(ModelOne.SubModelOne(someVar: 2, otherVar: 1))
}
}
First downcast the self.data to ModelOne then call setSub function
if var data = self.data as? ModelOne {
data.setSub(ModelOne.SubModelOne(someVar: 2, othervar: 1))
}
#Shadow of is right. You try to mutate a temporary structure which is impossible and most of the time useless as it will be released once the mutation done. It's in fact a similar issue to trying to modify the return struct of a function. (see answer here : Cannot assign to property: function call returns immutable value)
In Swift 3, in my case, I was able to resolve the error just by changing struct to a class object.