I'll start my saying that I'm inexperienced with Swinject.
I'm trying to figure out why Swinject.graphIdentier instances are constantly growing in my app.
In my case when I enter a ViewController I create n instances of MyClass.
n can be a different amount each time the screen is visited.
When I leave the view controller all instances of MyClass are deallocated (proven by observing allocations profiler).
The thing that I don't understand is why instances of Swinject.graphIdentier continue to grow.
Should GraphIdentifers in swinject ever be cleanedup and if so how can I do that?
Below is a stripped down, contrived example of my code.
class MyClass {
}
container.register(MyClass.self) {_ in
return MyClass()
}
//Graph Identifier Count goes up
func addItems() {
let newItem = AppAssembler.resolver.resolve(MyClass.self)
items.append(newItem)
}
//Graph Identifier count never goes down
func removeItems() {
items.removeAll()
}
Related
I have the following code:
class Problem{
init(){
print("Problem init");
}
deinit{
print("Problem deinit");
}
}
var list = Problem();
The output:
Problem init
The following causes the program to call deinit:
class Problem{
init(){
print("Problem init");
}
deinit{
print("Problem deinit");
}
}
do {
var list = Problem();
}
Questions:
Why isn't deinit called the first time?
Is there a way to guarantee that deinit will always be called for Problem in code that I have not control of how it is written(i.e., user code)?
P.S. I know there is most likely an obvious reason that I, as a programmer that is new to Swift, have overlooked.
It is because of the difference in Scopes between these two example that you create by adding the do-block.
In the first scenario, when that code is ran, an instance of Problem is created (initialized) at a Global Scope (outside of a class or struct definition in Swift) and then it just sits there. The program does not end and it is never de-initialized.
In the second scenario, you create the instance of Problem inside a the do-block, so it's scope is limited to inside that block. When the do-block ends, the instance is dereferenced, and thus de-initialized.
I can see many examples of retain cycles in Swift. However many of them are incorrect, and reading the documentation does not make really simple examples that I can follow.
For the example:
class Dog {
func bark() {
print ("YAP")
}
}
var dog = Dog()
let doSomething = {
dog.bark()
}
doSomething()
Does the closure doSomething cause a retain cycle? I understand that the closure will execute quickly, but that is not the question. Does this inherently cause a retain cycle?
There is no retain cycle in the program you posted.
What is a retain cycle?
Consider each object (including each closure) in your program as one vertex in a directed graph. Consider a strong reference from object (or closure) A to object (or closure) B as an edge from A to B in the graph.
A retain cycle is a cycle in the graph: a path containing at least one edge (strong reference) that leads from a vertex back to itself.
For example, a typical retain cycle looks like this:
A view controller always has a strong reference to its view (if the view has been loaded). In this example, the view controller created a closure. The closure captured (has a strong reference to) the view controller. The view controller then stored the closure in a property on the view, creating a retain cycle.
What is the retain graph of your program?
Here's the retain graph of your program:
There are no retain cycles in this graph.
Here is another "example" that runs outside of playground to showcase a retain cycle with a closure:
class ClosureClassStrongRefCycle {
let str : String
lazy var printStr: () -> () = { // self is captured
print("\(self.str)")
}
init(str: String) {
self.str = str
}
deinit {
print("ClosureClassStrongRefCycle is being deallocated")
}
}
Now when you call your class like this :
do {
let myClassWithClosureStrongCycle = ClosureClassStrongRefCycle(str: "closure class strong cycle")
myClassWithClosureStrongCycle.printStr()
} // 'myClassWithClosureStrongCycle' is NEVER deallocated -> Strong reference cycle between this class and it's closure
the instance of ClosureClassStrongRefCycle retains itself because the closure within it retains self
finally if you want to get rid of the retain cycle, you can add unowned self like this :
lazy var printStr: () -> () = { [unowned self] in // Unowned copy of self inside printStr
print("\(self.str)")
}
I've just started studying Rxswift lately. And there's this one question that's been bothering me since. Take this code snippet for example:
class MyClass {
var v = Variable("")
var bag = DisposeBag()
func subscribe() {
let ob = v.asObservable()
ob.subscribe(onNext: { (value) in
print("Value changed: " + value)
}).disposed(by: bag)
}
}
What bothers me is, where/who is the real observer in the scenario of subscribe() method? In term of objects, here we have ob who acts as an observable, but I can't really see the observer object anywhere.
Can anyone pls brighten my mind?
The observer in the example above is really the closure which you provide to the subscribe(onNext:) function.
Of course, how long that closure sticks around is determined by the lifetime of your DisposeBag: when your instance of MyClass dies, bag dies, and therefore the closure dies. For this reason, you may find people calling your instance of MyClass the "observer".
I'm learning more about Swift and came across the defer statement recently, which seems really intriguing to me. However I don't really understand it's purpose. Coming from C++ I would have implemented the same functionality using deallocation function and as a matter of fact, as Swift is ARC, it can do the same.
Let's say FooData and BarData both work with data that needs to deallocated.
class FooData {
deinit {
print("FooData being deallocated")
}
}
class BarData {
}
func baz() -> Int {
var a = FooData()
var b = BarData()
defer { print("BarData being deallocated") }
/* sensitive operations that could throw at any time */
return 0
}
baz()
// BarData being deallocated
// FooData being deallocated
So what's the advantage of the defer approach over the deinit approach? Just thinking about using defer for anything besides resource cleanup makes my head hurt...
You are seeing as different but there are not, defer was introduced by Apple as a safe and easy way to handle the clean up before returning, but defer only works for scopes. So let me explain better, if you have some scope defined inside a function an the variable you have created exist only inside the scope you cannot access from the deinit, for example:
func resizeImage(url: NSURL) -> UIImage? {
// ...
let dataSize: Int = ...
let destData = UnsafeMutablePointer<UInt8>.alloc(dataSize)
defer {
destData.dealloc(dataSize)
}
var destBuffer = vImage_Buffer(data: destData, ...)
// scale the image from sourceBuffer to destBuffer
var error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, ...)
guard error == kvImageNoError
else { return nil }
// create a CGImage from the destBuffer
guard let destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, ...)
else { return nil }
// ...
}
In this case it doesn't make sense define the variable destData as global and we need to deallocate once we finish of work with it, so defer it's the choice.
I think deinit it can be used for more global scope, for example when you implement the Key-Value Observer using NSNotificationCenter or something else you need.
I hope this help you.
Using defer inside a method means that its work will be executed as the method is exiting.
override func viewDidLoad() {
super.viewDidLoad()
print("Step 1")
myFunc()
print("Step 5")
}
func myFunc() {
print("Step 2")
defer { print("Step 3") }
print("Step 4")
}
"Step 1", "Step 2", "Step 4", "Step 3", "Step 5" – steps 3 and 4 are switched because 3 is deferred until the myFunc() method ends, i.e. when it goes out of scope programmatically.
About deinit, this is used to run code before deinitialization. The deinit code is run automatically. Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself.
class Item {
init() {
print("init called")
}
deinit {
// Called whenever class stops existing.
print("deinit called")
}
}
// Create optional Item variable.
var i: Item? = Item()
// Set optional to nil to force deinit.
i = nil
In programming some functions always appear in pairs. For example, opening a connection and closing that connection, locking a mutex and unlocking a mutex, incrementing a counter, decrementing a counter, allocating memory, deallocating memory.
The pattern usually looks like this:
lock()
... do something ...
unlock()
The middle part can be complicated and long. There can be returns (e.g. for failed preconditions and Swift recommends this pattern with its guard). Sometimes it's very hard not to forget to include that unlock() in all execution paths.
One way to solve the situation nicely is using a helper function:
func doSomething() {
... do something with returns ...
}
lock()
doSomething()
unlock()
but that's not always possible, e.g. when you have several nested objects.
In C the same pattern was often solved with goto:
x = malloc(...);
y = malloc(...);
if (!precondition) {
goto end;
}
... some code ...
end:
free(y);
free(x);
Modern languages came with a better approach which in Swift is implemented using defer (you can also find defer in Go, for example).
lock()
defer {
unlock()
}
... some code ...
This approach has several benefits:
You can have the calls together, which increases readability and makes it very hard to forget the second call.
All returns, precondition checks, error handling will leave the code in correct state because unlock will be always called correctly. This is similar to finally in exception handling in Java (and other languages)
If you are asking about the difference from deinit, it works in a similar way. However defer can work in functions while deinit works only for classes.
Also note that you could reimplement defer using deinit but the usage would be more complicated and the behavior less predictable.
defer could be called conditionally what is impossible to implement with deinit
var i = 1
func foo()->Int {
if i == 1 {
defer {
i = 0
}
}
return i + 1
}
print("foo:", foo(), "i:", i)
Consider a database transaction. You want to close the connection when you're done, but you want to keep the object around to reinstate connections in the future:
stuct foo {
let db = Database()
func useDatabase() throws {
let connection = db.openConnection()
defer {
// close conenction, but keep db around for future use
connection.close
}
try connection.thisCanThrow()
}
}
This is just one example, but there are many like it. In particular, a lot of cases arise where you want to model the restricted lifespan of a state, without binding it tightly to an object's life time.
C++ heavily relies on RAII. Swift is certainly capable of adhering to the same paradigm, but it can also go beyond it with defer.
I'm trying to access a C API from Swift that requires the use of C callbacks.
typedef struct {
void * info;
CFAllocatorRetainCallBack retain;
CFAllocatorReleaseCallBack release;
} CFuncContext;
typedef void (* CFuncCallback)(void * info);
CFuncRef CFuncCreate(CFuncCallback callback, CFuncContext * context);
void CFuncCall(CFuncRef cfunc);
void CFuncRelease(CFuncRef cfunc);
CFuncCreate stores the callback and context on the heap (using malloc), then calls the retain callback to retain the info pointer. CFuncCall simply invokes the callback for demonstration purposes, and CFuncRelease calls the release callback, then frees the memory.
In the Swift code I want to use a dedicated object for info that keeps a weak reference back to my main object. When the main object is deinited, CFuncRelease is called to also clean up the C API memory.
This way, even if the C API decides to perform some delayed callbacks from different run loops, it always has a valid info pointer until it decides to invoke the release callback when it is finally done. Just some defensive programming :)
The info object has this structure:
final class CInfo<T: AnyObject> {
/// This contains the pointer back to the main object.
weak private(set) var object: T?
init(_ object: T) {
self.object = object
}
/// This variable is used to hold a temporary strong
/// `self` reference while retainCount is not 0.
private var context: CInfo<T>?
/// Number of times that `retain` has been called
/// without a balancing `release`.
private var retainCount = 0 {
didSet {
if oldValue == 0 {
context = self
}
if retainCount == 0 {
context = nil
}
}
}
func retain() {
++retainCount
}
func release() {
--retainCount
}
}
My main object SwiftObj uses the C API.
final class SwiftObj {
typealias InfoType = CInfo<SwiftObj>
private lazy var info: InfoType = { InfoType(self) }()
private lazy var cFunc: CFuncRef = {
var context = CFuncContext(
info: &self.info,
retain: { UnsafePointer<InfoType>($0).memory.retain(); return $0 },
release: { UnsafePointer<InfoType>($0).memory.release() }
)
return CFuncCreate(
/* callback: */ cFuncCallback,
/* context: */ &context
)
}()
func call() {
CFuncCall(cFunc)
}
deinit {
CFuncRelease(cFunc)
}
init() {
call()
}
}
func cFuncCallback(info: UnsafeMutablePointer<Void>) {
print("==> callback from C")
}
In my testing code, I first allocate a SwiftObj via an IBAction. Then, I set the reference back to nil again via a second IBAction.
The automated cleanup code should now properly deinit the SwiftObj, and from there the C API should be notified that it should clean up its memory. Then, the release callback on the info pointer should be invoked, which results in the info pointer's reference count reaching zero, and also deallocating the info pointer.
However, the deinit theory doesn't seem to work out. After SwiftObj's final reference is removed, another reference is added back when the release callback closure is invoked, and another reference is re-added during the CInfo.release method (as observed using Instrument's Allocations tracker). Behaviour also depends on the timings - e.g. the number of log statements.
With a minimal sample like the one below, it crashes immediately in the initial release callback closure with either of these two messages depending on the timings - first one is more common, second one can be achieved by a fast space tab space if you are lucky. Maybe there's even more - as I said, in my full example if you put in enough log statements sometimes it prolongs the final cleanup of the SwiftObj enough so that you can see the actual resurrection happening.
EXC_BAD_ACCESS (code=1, address=0x0)
EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
Minimal example can be downloaded here:
https://scriptreactor.com/Resurrection.zip
Run, then hit the Start button, then hit the Stop button. Welcome to the nightmare.
Instruments' Allocations view can also be quite interesting.
Seems like a compiler bug. Workaround is to remove the lazy attribute of the info instance variable.
https://bugs.swift.org/browse/SR-74