When to use static constant and variable in Swift? - ios

There are some posts for how to write code for static constant and static variable in Swift. But it is not clear when to use static constant and static variable rather than constant and variable. Can someone explain?

When you define a static var/let into a class (or struct), that information will be shared among all the instances (or values).
Sharing information
class Animal {
static var nums = 0
init() {
Animal.nums += 1
}
}
let dog = Animal()
Animal.nums // 1
let cat = Animal()
Animal.nums // 2
As you can see here, I created 2 separate instances of Animal but both do share the same static variable nums.
Singleton
Often a static constant is used to adopt the Singleton pattern. In this case we want no more than 1 instance of a class to be allocated.
To do that we save the reference to the shared instance inside a constant and we do hide the initializer.
class Singleton {
static let sharedInstance = Singleton()
private init() { }
func doSomething() { }
}
Now when we need the Singleton instance we write
Singleton.sharedInstance.doSomething()
Singleton.sharedInstance.doSomething()
Singleton.sharedInstance.doSomething()
This approach does allow us to use always the same instance, even in different points of the app.

There are some posts for how to write code for static constant and static variable in Swift. But it is not clear when to use static constant and static variable rather than constant and variable. Can someone explain?
When you define a static var/let into a class (or struct), that value will be shared among all the instances (or values).
static variables/class are variables can be accessed without need of creation of any instance/object.
class Human {
static let numberOfEyes = 2 //human have only 2 eyes
static var eyeDefect = false //whether human have side-effect or not. he can have defect later so its variable
//other variables and functions
}
//you can access numberOfEyes like below no object of Human is created
print(Human.numberOfEyes)
print(Human.eyeDefect)
//Object of Human
let john = Human()
I think you know difference between constant and variable. In short, constant is that whose value never changes; numberOfEyes in above example and variable is that whose value changes; eyeDefect in above example.
static constant or variables are placed in memory(RAM) separate then the Objects. i.e. numberOfEyes have different memory space allocated than John object, its not inside John.
now, when to use static constants/variables:
When you use singleton design pattern: static let sharedInstance = APIManager()
class APIManager(){
static let sharedInstance = APIManager()
//Your other variables/functions here below
}
//Use it as to get singleton instance of APIManager from anywhere in your application
let instanceOfAPIManager = APIManager.sharedInstance
When you need value of anything that is globally the same without need to make instance of the class under which it is defined like numberOfEyes in human class.
Use of static variables/constants are not much recommended because of memory issues because once it's instantiated/assigned, it remains in memory until your application gets removed from the memory. I have found till now the best place to use static variables/constants is only while making singleton pattern and sometimes pointers for other normal variables and constants don't use static because: memory issue, it will be difficult to run unit testing in your code with static variables/constants. Not recommended to use as like in Human class also. instead use them as just constant or variables and access them by making instance.
class Human {
let numberOfEyes = 2 //human have only 2 eyes
var eyeDefect = false //whether human have side-effect or not. he can have defect later so its variable
//other variables and functions
}
//you can access numberOfEyes like below if you need just those values.
print(Human().numberOfEyes)
print(Human().eyeDefect)

Static constants and variables do belong to the class itself, not to a particular instance. A class can also have static methods that can be called without creating an instance of a class.
So when you have a class MyClass with a static var x, you can also access it through MyClass.x directly. x will be shared among all instances of a class

This is more of an important comment:
class Person {
static var name = "Static John" // a property of Person 'type'
var name = "Alex" // a property of Person 'instance'
var nonStaticName = "Peter"
static var staticName = "Sara"
static func statFunc() {
let x = Person.name // Static John
let y = name // Static John or Alex?! Static John!!!!
let r = staticName // Sara
let k = nonStaticName // ERROR: instance member 'nonStaticName' cannot be used on type 'Person'
// The compiler is like: I'm referring to the `nonStaticName` property of which instance?! There is no instance! Sorry can't do!
}
func nonStaticFunc() {
let x = Person.name // Static John
let y = name // Static John or Alex?! Alex!!! Because we're in a instance scope...
let k = nonStaticName // Obviously works
let r = staticName // ERROR: static member 'staticName' cannot be used on instance of type 'Person'. Person.staticName will work
}
}
Interesting observations:
First:
static var name = "Static John" // a property of Person 'type'
var name = "Alex" // a property of Person 'instance'
creates no conflicts.
Second:
You can't ever use instance variables inside static variables. You can use static variables inside instance functions if you refer to it by prefixing it with the type ie do Person.name, whereas
static variables can be accessed inside static functions with or without prefixing the type ie Person.staticName or staticName both work.

Related

.self after struct type in Swift

I’m confused by a line of code found in the Metal example where the memory pointer is bound to a type.
uniforms = UnsafeMutableRawPointer(uniformBuffer.contents()).bindMemory(to: Uniforms.self, capacity: 1)
My confusion is the .self after the Uniforms type. Uniforms is a struct defined in an Objective-C file and the code wont run without .self being in the call. Why is that necessary?
The .self returns the metatype instance for the corresponding type. Think of it as a typesafe type identifier (e.g., way safer than using a string for that). You can then safely call the available initializers, static methods, static properties on such metatype instance.
For instance, you could store it in a variable as well:
let metatype: Uniforms.Type = Uniforms.self
and Uniforms.Type is the actual metatype (i.e., the type's type).
Metatype crash course. A very quick example to get a feel of how this meta stuff might be actually useful:
class Super {
let id: Int
required init(id: Int) { self.id = id }
}
class SubA: Super { ... }
class SubB: Super { ... }
let subclass: Super.Type = SubA.self
and then, later on, use subclass to create an instance without hardcoding the actual subclass type name:
let obj = subclass.init(id: 123) // new SubA instance.
In Swift, .self could be used on a type to extract its meta type or on an instance of a type. Example, use .self to get the meta type and pass it to the API:
self.tableView.registerClass(
UITableViewCell.self, forCellReuseIdentifier: "myUIViewCell")

Inout parameters don't have the same address

I have three classes A, B and C. A has a resource called rA. What I am trying to achieve is that all of those instances have a reference to the exact same resource.
So to concrete in Swift terms:
Class A has a property called foo:
private var foo : [Bar] = [Bar]() // shared resource
Class B has a property called foo which is passed into the initializer as an inout parameter:
private var foo : [Bar]!
init(inout foo:[Bar]){
self.foo = foo
}
Class C is analogous to Class B
How come, if I pass foo from Class A to Class B (or C) the address changes ?
In A I would pass it to B (or C) like so:
let b = B(foo: &self.foo)
When I print the address after initialization of foo in A it gives me a different address than after assignment in B.
class A{
private var foo = [Bar]()
func someFunc(){
NSLog("\n\n [A] \(unsafeAddressOf(self.foo))\n\n") // different from output in B
let b = B(foo: &self.foo)
}
}
class B{
private var foo: [Bar]!
init(inout foo: [Bar]){
self.foo = foo
NSLog("\n\n [B] \(unsafeAddressOf(self.foo))\n\n")
}
}
Any ideas why this is the case ?
Swift arrays are value types, therefore in
self.foo = foo
you assign the value of foo to self.foo. This are two independent arrays now
(even if the actual elements are copied only when one of the arrays is mutated).
Also you cannot take the address of a Swift array with unsafeAddressOf() because
that function takes an AnyObject parameter which is an instance of a class, i.e.
a value type. In
unsafeAddressOf(self.foo)
the Swift compiler actually bridges the Swift array to an NSArray. As demonstrated
in Swift, Strings and Memory Addresses,
this may or may not result in the same object when done repeatedly. In any case,
the printed address is not the storage location of the Swift array.
If you need a real reference which you can pass around then you can wrap the array in a class.
Using NS(Mutable)Array might also be an option, but then you lose many Swift features.

How to access class constants and variables

Why can I not perform operations with a variable or constant at the class level? Is this not allowed or is there a keyword I need to use to access them? Is this bad practice?
Controller:
class ViewController: UIViewController {
let one = 1
let two = 2
var sum = one + two
}
Error:
ViewController.Type does not have a member named 'one'
Class variables and constants must be static, e.g., static let one = 1.
Here it suffices for the two let constants to be static for them to be usable in initializing both class and instance variables. The following works for me:
class MyClass {
static let one = 1
static let two = 2
static var sum = one + two
var instanceProduct = one * two
}
MyClass.one
MyClass.sum
MyClass().instanceProduct
Note that in the above example you can do MyClass.sum = 5. If you meant the sum to be constant as well, simply change it to static let sum = one + two.
The requirement is that the constants you use outside of any functions and closures be declared static let. The implication of this is that they are truly constant for the entire class. If you need instance-specific constants, you cannot use them outside of functions or closures (as you've noticed) – as a workaround for a variable sum I would suggest a lazy variable initialized by a closure:
class MyClass {
let one: Int // value given in `init`
let two = 2
lazy var sum: Int = { self.one + self.two }()
init(one: Int = 1) {
self.one = one
}
}
MyClass().sum // 3
MyClass(one: 2).sum // 4
Simple fix
override func viewDidLoad() {
super.viewDidLoad()
var result = one + two
}

Trying to understand type properties such as static and class keyword of swift

I am currently reading The Swift Programming Language, and when it reaches to Type Properties, it says “You define type properties for value types with the static keyword, and type properties for class types with the class keyword. ” But what static means and what id does? I just can't get a clue.
Type properties are properties that are associated with the type, meaning you don't need an actual instance of the class or struct to access them. static is used to define such a property in structs. For example:
struct Constants {
static let pi = 3.1416
static let e = 2.71828
let phi = 1.618
}
println(Constants.pi) // prints "3.1416"
println(Constants.e) // prints "2.71828"
println(Constants.phi) // Error: 'Constants.Type' does not have a member named 'phi'
println(Constants().phi) // prints "1.618" when we create an instance

Swift class "MyClass" does not have a member Named "My_Var" [duplicate]

This question already has answers here:
How to initialize properties that depend on each other
(4 answers)
Closed 8 years ago.
I created a class in Swift like below, but it gives error:
'ApiUrls.Type' does not have a member named 'webUrl'
Here is my code:
import UIKit
class ApiUrls {
let webUrl:NSString = "192.168.0.106:8888"
var getKey:NSString = webUrl + NSString("dev/sys/getkey") // here comes the error ApiUrls.Type' does not have a member named 'webUrl
}
What's wrong in it?
You cannot initialize an instance property with the value of another property, because self is not available until all instance properties have been initialized.
Even moving the properties initialization in an initializer doesn't work, because getKey relies on webUrl, so getKey cannot be initialized until itself is initialized.
I see that webUrl is a constant, so maybe it's a good idea to make it a static property - classes don't support statics as of yet, so the best way is to use a private struct:
class ApiUrls {
private struct Static {
static let webUrl: String = "192.168.0.106:8888"
}
var getKey: String = Static.webUrl + "dev/sys/getkey"
}
Also, unless you have a good reason, it's better to use swift strings and not NSString.
As far as I know, you cannot initialise variables like that in the class definition.
Try declaring your variables as
let webUrl:NSString = "192.168.0.106:8888"
var getKey:NSString = ""
and add this in viewDidLoad
getKey = webUrl + NSString("dev/sys/getkey")

Resources