Where Singleton object is allocated? - swift

I wanted to know where myClass objects allocated exactly so I drew allocation flow
class MyClass {
static let shared = MyClass()
private init() { }
}
let myClass = MyClass.shared
myClass constant is allocated in Stack
myClass constant point to Heap where MyClass is allocated
MyClass.shared static property point to MyClass() where allocated in Heap
Is this flow right? Am I misunderstood something?

Swift allocates storage for MyClass.shared in the data segment, initialized to nil. The data segment's layout and initial contents are defined by the executable file. Historically, the heap started immediately at the end of the data segment, but on modern 64-bit systems with address space layout randomization (ASLR), I don't know if that's still true.
Swift also allocates a swift_once_t in the data segment to record whether MyClass.shared has been initialized yet.
Swift generates a getter function for MyClass.shared in the code segment. The getter function uses the swift_once_t to initialize the storage of MyClass.shared the first time the getter is called. It looks approximately like this:
var _storage_MyClass_shared: MyClass? = nil
var _once_MyClass_shared: swift_once_t = .init() // essentially, false
func _getter_MyClass_shared() -> MyClass {
swift_once(&_once_MyClass_shared, {
_storage_MyClass_shared = MyClass()
})
return _storage_MyClass_shared!
}
The instance of MyClass is stored on the heap. It starts with a word containing the isa pointer (to the MyClass metadata), followed by a word containing (usually) reference counts, followed by storage for the object's instance variables. In your case, there are no instance variables, so there is no additional storage. The blue box labeled Myclass() in your diagram, and the arrow pointing to it, do not exist.
If myClass is at top-level (not inside a method or data type declaration), then it is also stored in the data segment along with another swift_once_t that tracks whether it's been initialized, and Swift generates a getter for it in the code segment.
If myClass is an instance variable of a data type, then it is stored as part of its containing object, which may be either on the stack or the heap (in the case of a struct, enum, or tuple) or always on the heap (in the case of a class or actor).
If myClass is a local variable in a function, then it is stored on the stack.

Related

Swift static property initilizers are lazy why I could declared it as a constant

As far as I known (see reference A), Static property initilizers are lazy, and I found the following description by the office documents
You must always declare a lazy property as a variable (with the var
keyword) because its initial value might not be retrieved until after
instance initialization completes. Constant properties must always
have a value before initialization completes, and therefore cannot be
declared as lazy.
From the above information, I think I couldn't define the static property as a constant variable and I made a tryout, it turns out I can do that without triggering any error from the compiler.
Example:
class Person {
static let firstNaID = "First Name"
static let lastNaID = "Last Name"
}
Question: Is this a bug of the Swift 3.0.1 or I was wrong.
Reference A: Neuburg. M.2016. IOS 10 Programming Fundamental with Swift. P127
Thanks for your time and help
Neuburg M. is drawing a distinction between static properties and instance properties. You are pretending to ignore that distinction. But you cannot ignore it; they are totally different things, used for different purposes.
In this code:
class Person { // let's declare a static property
static let firstNaID = "First Name"
}
... firstNaID is already lazy. But now try to do this:
class Person { // let's declare an instance property
lazy let firstNaID : String = "First Name" // error
}
You can't; as things stand (up thru Swift 3.1), you have to say lazy var instead — and when you do, you get a lazy instance property.
Your static let declaration thus doesn't accomplish what lazy let wanted to accomplish, because a static property is not an instance property.
You are talking about type properties
Form the same chapter of the documentation
Type Properties
... Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use ...
Stored type properties can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties.
NOTE
...
Stored type properties are lazily initialized on their first access. They are guaranteed to be initialized only once, even when accessed by multiple threads simultaneously, and they do not need to be marked with the lazy modifier.

Swift's memory management

I'm a little confused regarding Swift's memory management. Can someone explain to me how come kid1 always stays at the same memory address? Even when I do kid1=kid2 or initialize a new object?
Your code prints the memory location of the kid1 variable,
and that does not change if you assign a new value to the variable.
If Kid is a reference type (class) then you can use
ObjectIdentifier to get a unique identifier for the class instance
that the variable references:
var kid1 = Kid(name: "A")
var kid2 = Kid(name: "B")
print(ObjectIdentifier(kid1)) // ObjectIdentifier(0x0000000100b06220)
print(ObjectIdentifier(kid2)) // ObjectIdentifier(0x0000000100b06250)
kid1 = kid2
print(ObjectIdentifier(kid1)) // ObjectIdentifier(0x0000000100b06250)
The object identifier happens to be the address of the pointed-to
instance, but that is an undocumented implementation detail.
If you need to convert an object reference to a real pointer
then you can do (compare How to cast self to UnsafeMutablePointer<Void> type in swift)
print(Unmanaged.passUnretained(kid1).toOpaque())
Why kid1 is pointing to the same MemoryAddress each time?
In general, a class is a reference type. Which means, all instances of a class will share a single copy of data.
I.e, it's like a mutable data, if you change a data at any once instance of class, then it will affect that change to all its dependent instances.
It mainly deals with the memory addresses.
I think you have declared your class like below:
class Kid {
var name: String?
init(name:String) {
self.name = name
}
}
then for
var kid1 = Kid(name: "A"): For kid1 instance it will assign some memory address, say <Kid: 0x60400024b400>
var kid2 = Kid(name: "B"): For kid2 instance it will assign some other memory address, say <Kid: 0x60400024b760>
when you do kid1 =kid2: kid1 memory address will get changed to kid2 memory address. So, kid1 and kid2 will pointing to same memory address.
kid1.name = "C": now if a change kid1.name,..it will reflect to kid2.name value also,because both are pointing to same memory address.
Therefore you get:
kid1.name == "C"
kid2.name == "C"
There are 2 categories that are supported by Swift (Value Types, Reference Type). We have 3 different behaviours that we can have for those types - Copy by reference, Copy by value and Copy-on-Write. Classes as in your case are using copy by reference which means both instances point to same address - share a single copy of data. More details are described in my post about swift memory management and performance, I go as deep as binary values in the memory. I hope it helps:
Swift Memory Management and Performance

Struct cannot have a stored property that references itself [duplicate]

Reference cycles in Swift occur when properties of reference types have strong ownership of each other (or with closures).
Is there, however, a possibility of having reference cycles with value types only?
I tried this in playground without succes (Error: Recursive value type 'A' is not allowed).
struct A {
var otherA: A? = nil
init() {
otherA = A()
}
}
A reference cycle (or retain cycle) is so named because it indicates a cycle in the object graph:
Each arrow indicates one object retaining another (a strong reference). Unless the cycle is broken, the memory for these objects will never be freed.
When capturing and storing value types (structs and enums), there is no such thing as a reference. Values are copied, rather than referenced, although values can hold references to objects.
In other words, values can have outgoing arrows in the object graph, but no incoming arrows. That means they can't participate in a cycle.
As the compiler told you, what you're trying to do is illegal. Exactly because this is a value type, there's no coherent, efficient way to implement what you're describing. If a type needs to refer to itself (e.g., it has a property that is of the same type as itself), use a class, not a struct.
Alternatively, you can use an enum, but only in a special, limited way: an enum case's associated value can be an instance of that enum, provided the case (or the entire enum) is marked indirect:
enum Node {
case None(Int)
indirect case left(Int, Node)
indirect case right(Int, Node)
indirect case both(Int, Node, Node)
}
Disclaimer: I'm making an (hopefully educated) guess about the inner workings of the Swift compiler here, so apply grains of salt.
Aside from value semantics, ask yourself: Why do we have structs? What is the advantage?
One advantage is that we can (read: want to) store them on the stack (resp. in an object frame), i.e. just like primitive values in other languages. In particular, we don't want to allocate dedicated space on the heap to point to. That makes accessing struct values more efficient: we (read: the compiler) always knows where exactly in memory it finds the value, relative to the current frame or object pointer.
In order for that to work out for the compiler, it needs to know how much space to reserve for a given struct value when determining the structure of the stack or object frame. As long as struct values are trees of fixed size (disregarding outgoing references to objects; they point to the heap are not of interest for us), that is fine: the compiler can just add up all the sizes it finds.
If you had a recursive struct, this fails: you can implement lists or binary trees in this way. The compiler can not figure out statically how to store such values in memory, so we have to forbid them.
Nota bene: The same reasoning explains why structs are pass-by-value: we need them to physically be at their new context.
Quick and easy hack workaround: just embed it in an array.
struct A {
var otherA: [A]? = nil
init() {
otherA = [A()]
}
}
You normally cannot have a reference cycle with value types simply because Swift normally doesn't allow references to value types. Everything is copied.
However, if you're curious, you actually can induce a value-type reference cycle by capturing self in a closure.
The following is an example. Note that the MyObject class is present merely to illustrate the leak.
class MyObject {
static var objCount = 0
init() {
MyObject.objCount += 1
print("Alloc \(MyObject.objCount)")
}
deinit {
print("Dealloc \(MyObject.objCount)")
MyObject.objCount -= 1
}
}
struct MyValueType {
var closure: (() -> ())?
var obj = MyObject()
init(leakMe: Bool) {
if leakMe {
closure = { print("\(self)") }
}
}
}
func test(leakMe leakMe: Bool) {
print("Creating value type. Leak:\(leakMe)")
let _ = MyValueType(leakMe: leakMe)
}
test(leakMe: true)
test(leakMe: false)
Output:
Creating value type. Leak:true
Alloc 1
Creating value type. Leak:false
Alloc 2
Dealloc 2
Is there, however, a possibility of having reference cycles with value types only?
Depends on what you mean with "value types only".
If you mean completely no reference including hidden ones inside, then the answer is NO. To make a reference cycle, you need at least one reference.
But in Swift, Array, String or some other types are value types, which may contain references inside their instances. If your "value types" includes such types, the answer is YES.

Reference cycles with value types?

Reference cycles in Swift occur when properties of reference types have strong ownership of each other (or with closures).
Is there, however, a possibility of having reference cycles with value types only?
I tried this in playground without succes (Error: Recursive value type 'A' is not allowed).
struct A {
var otherA: A? = nil
init() {
otherA = A()
}
}
A reference cycle (or retain cycle) is so named because it indicates a cycle in the object graph:
Each arrow indicates one object retaining another (a strong reference). Unless the cycle is broken, the memory for these objects will never be freed.
When capturing and storing value types (structs and enums), there is no such thing as a reference. Values are copied, rather than referenced, although values can hold references to objects.
In other words, values can have outgoing arrows in the object graph, but no incoming arrows. That means they can't participate in a cycle.
As the compiler told you, what you're trying to do is illegal. Exactly because this is a value type, there's no coherent, efficient way to implement what you're describing. If a type needs to refer to itself (e.g., it has a property that is of the same type as itself), use a class, not a struct.
Alternatively, you can use an enum, but only in a special, limited way: an enum case's associated value can be an instance of that enum, provided the case (or the entire enum) is marked indirect:
enum Node {
case None(Int)
indirect case left(Int, Node)
indirect case right(Int, Node)
indirect case both(Int, Node, Node)
}
Disclaimer: I'm making an (hopefully educated) guess about the inner workings of the Swift compiler here, so apply grains of salt.
Aside from value semantics, ask yourself: Why do we have structs? What is the advantage?
One advantage is that we can (read: want to) store them on the stack (resp. in an object frame), i.e. just like primitive values in other languages. In particular, we don't want to allocate dedicated space on the heap to point to. That makes accessing struct values more efficient: we (read: the compiler) always knows where exactly in memory it finds the value, relative to the current frame or object pointer.
In order for that to work out for the compiler, it needs to know how much space to reserve for a given struct value when determining the structure of the stack or object frame. As long as struct values are trees of fixed size (disregarding outgoing references to objects; they point to the heap are not of interest for us), that is fine: the compiler can just add up all the sizes it finds.
If you had a recursive struct, this fails: you can implement lists or binary trees in this way. The compiler can not figure out statically how to store such values in memory, so we have to forbid them.
Nota bene: The same reasoning explains why structs are pass-by-value: we need them to physically be at their new context.
Quick and easy hack workaround: just embed it in an array.
struct A {
var otherA: [A]? = nil
init() {
otherA = [A()]
}
}
You normally cannot have a reference cycle with value types simply because Swift normally doesn't allow references to value types. Everything is copied.
However, if you're curious, you actually can induce a value-type reference cycle by capturing self in a closure.
The following is an example. Note that the MyObject class is present merely to illustrate the leak.
class MyObject {
static var objCount = 0
init() {
MyObject.objCount += 1
print("Alloc \(MyObject.objCount)")
}
deinit {
print("Dealloc \(MyObject.objCount)")
MyObject.objCount -= 1
}
}
struct MyValueType {
var closure: (() -> ())?
var obj = MyObject()
init(leakMe: Bool) {
if leakMe {
closure = { print("\(self)") }
}
}
}
func test(leakMe leakMe: Bool) {
print("Creating value type. Leak:\(leakMe)")
let _ = MyValueType(leakMe: leakMe)
}
test(leakMe: true)
test(leakMe: false)
Output:
Creating value type. Leak:true
Alloc 1
Creating value type. Leak:false
Alloc 2
Dealloc 2
Is there, however, a possibility of having reference cycles with value types only?
Depends on what you mean with "value types only".
If you mean completely no reference including hidden ones inside, then the answer is NO. To make a reference cycle, you need at least one reference.
But in Swift, Array, String or some other types are value types, which may contain references inside their instances. If your "value types" includes such types, the answer is YES.

How do I use objective-c-runtime's object_getIvar & object_setIvar in swift?

Does anybody know why I get BAD_ACCESS on getting & setting of my iVars with the following code ?
class myClass: NSObject {
var model = "Unspecified"
override init() {
super.init()
var key: NSString = "model"
var aClass : AnyClass? = self
var ivar: Ivar = class_getInstanceVariable(aClass, key.UTF8String)
// Set
object_setIvar(aClass, ivar, "R56")
// Get
var value: AnyObject = object_getIvar(aClass, ivar)
}
}
myClass()
You get a bad access because Swift classes do not have traditional iVars anymore (try to grab a Swift class' iVar layout and see for yourself). But Swift classes are also Objective-C objects to the runtime, and there don't appear to be any paths excluding Swift classes in it.
What winds up happening is the runtime hands you a bogus iVar that it truly thinks points to a proper offset in the class definition (probably 0 or thereabouts because it doesn't exist). When you try to get said iVar, the runtime literally derefs you some of the object's bytes and tries to wrap it back up in an Objective-C pointer. Often this data has the tagged bit set unintentionally, and so often maps to tagged classes (in my tests I was reliably getting back a tagged pointer for what the runtime thought was NSMutableData).
Long story short: you can't do it anymore.