As everyone knows when using the awesomeness that is Firebase in iOS,
whenever you have observations in a view controller,,
var o: DatabaseReference?
var o2: DatabaseReference?
var o3: DatabaseReference?
it's essential that when that screen goes away, you must terminate all the observations...
private func clearObservations() {
print("\n\n clearing observations! \n\n")
if o != nil {
o?.removeAllObservers()
o = nil
}
if o2 != nil {
etc...
}
However!
After considerable testing, you cannot call clearObservations() in deinit - you must call it in viewDidDisappear (or some other logical place).
Again - it explicitly does not work in deinit.
My question, why would it be that actually this does not work in deinit?
BTW, you fire up a Firebase observor like this:
say, viewWillAppear#
o = Database.database().reference(withPath: "string")
o!.observe(.value, with: { (snapshot) in
self.blah(snapshot)
})
I believe your issue is likely that deinit is not being called at all and usually this kind of thing is because your observer closure is strongly retaining self and the closure is itself retained by the firebase service. That means your object can never die. You can break this kind of cycle with an unowned or weak capture.
To check if this is the case, put a print in your deinit. If the print does not get called when you expect then the object is not being released and you should run the memory debugger to see who else is pointing at it.
I've had the same issue before when forgetting to put unowned on a realm observe method.
Related
I'm considering making an iOS project in React Native. On iOS it's a big issue to find and fix so-called "retain cycles", i.e. when the two object store a strong reference to each other:
class Obj1 {
var delegate: Obj2?
}
class Obj2 {
var delegate: Obj1?
}
let obj1 = Obj1()
let obj2 = Obj2()
obj1.delegate = obj2
obj2.delegate = obj1
Does the React Native has a concept of a memory leak or retain cycle? Would the similar code in the JS counterpart create a retain cycle in React Native environment?
How about passing a closure capturing self? Would that also create a memory leak in React Native?
Summary:
Would the listed sample code (rewritten to JS) cause a memory leak in RN?
Would capturing self in a closure cause a memory leak?
You shouldn't really have two objects retaining strong references to each other, the delegate pattern is usually handled by having one strong and one weak reference, where the delegate is the weak one.
Now onto your questions:
Probably, but someone else might give you a better answer since I'm not entirely sure about RN.
Yes and no, depending on how you go about it.
If you use strong self, then definitely there will be a memory leak:
{ _ in
self.doSomething()
}
Better way is to use either weak self:
{ [weak self] _ in
guard let self = self else { return }
self.doSomething()
}
or unowned self if you can guarantee self is available in the closure at all times:
{ [unowned self] _ in
self.doSomething()
}
So here is my code
func retrieveAndAssignHighScoreFromCloudKit() {
let high = highScore
database.fetchRecordWithID(getRecordID(high), completionHandler: { [weak self]
(record: CKRecord?, error: NSError?) in
if error != nil {
print(self!.highScore)
// blah blah blah...
}
So in the first line of this function I am able to call highScore and assign it to something else but inside the closure Xcode is forcing me to use "self!." and in doing so somehow unwraps an optional even though my calling it prior shows me that it is not nil. I am really confused and there are a ton of basic questions about unwrapping optionals as nil but none that I've found seem to pertain to this.
Thank you very much!
EDIT: Tried switching "weak" to "unowned" and I crash on the same line and get "Thread 3: EXC_BREAKPOINT" despite not having and breakpoints. This message is displayed in green on another screen and does not highlight that line
Closures are not executed immediately.
When you pass a closure to the fetchRecordWithID method, you are telling it to execute that code when the method finishes fetching data, which can take time.
So far so good, right?
In the closure's capture list, you tell it to capture self as a weak reference. What's the purpose of this? To avoid a strong reference cycle, of course. If you don't, self holds a strong reference to the closure, and the closure holds a strong reference to self. As a result, both the closure and self will not be deinitialized.
A weak reference to self in the closure guarantees that self is deinitialized when the strong reference to the closure is broken.
I hope I've explained this well.
So now, let's say the strong reference to the closure is broken. As I said, self would be deinitialized as a result. After that, the thing finishes fetching data and it is now executing the completionHandler closure! Since self is already nil at this point, your app will crash when it reaches print(self!.highScore).
In other words, a weak reference to self implies that self can be nil. You need to unwrap it.
EDIT:
Maybe images can explain this better. (black arrows are strong references, green arrows are weak ones)
At first, it's like this:
When the strong reference is broken...
self becomes nil:
You can simply do something like this:
if let score = self?.highScore {
print(score)
// blah blah blah
} else {
// do something else, or nothing
}
Or just this:
print(self?.highScore)
You can use a strong reference when trying to use self like this:
func retrieveAndAssignHighScoreFromCloudKit() {
let high = highScore
database.fetchRecordWithID(getRecordID(high), completionHandler: { [weak self]
(record: CKRecord?, error: NSError?) in
if error != nil {
guard let strongSelf = self else {
return
}
print(strongSelf.highScore)
// blah blah blah...
}
}
}
I am new to ios development and i want to learn how memory leak will occur in swift or in Objective-C, can any one explain with small example?
Thanks
Small example:
class A {
var b: B!
deinit {
print("deinit of A")
}
}
class B {
var a: A!
deinit {
print("deinit of B")
}
}
do {
let a = A()
let b = B()
a.b = b
b.a = a
}
If you run this code (maybe in Playground), it will print nothing. It means that deinit never called for both objects and they just leaked.
But if you declare one of the properties as weak:
class A {
weak var b: B!
deinit {
print("deinit of A")
}
}
Then deinit will be called and you'll see messages in console.
Edit: add example with closures
Consider this example:
class C {
var f: (Void -> Void)!
deinit {
print("deinit for C")
}
}
do {
let c = C()
c.f = {
print(c)
}
}
c captures f, f captures c. So we got memory leak.
To deal with leaks in closures, you have 2 options – declare that captured object is weak or unowned. Like this:
do {
let c = C()
c.f = { [weak c] in
print(c)
}
}
Basically, you would use weak if it's possible for object to get out of existence and become nil when closure is called; but if you are sure object will still exist at this time, use unowned instead.
After I declare c as weak inside a closure, "deinit for C" is printed – means that everything deallocated successfully.
What this all means for you, the developer?
Almost all the time you don't have to worry about the memory management. It's done for you, automatically. Objects just exist when you need them and vanish when you don't. But there are 2 very common cases when you need to be careful and think about memory.
Delegation. It's common pattern in Cocoa and it could create retain cycles if done wrong. Always declare your delegate as weak unless you have a good reason not to.
Closures. Closure capture references for objects in surrounding scope and does it automatically, without notice. When implementing closure, chech if it will create retain cycle. If yes, declare problem variables as weak or unowned.
For further info I suggest you read official Apple Swift book which can be found in iBooks or here as a website.
Many posts seem to advise against notifications when trying to synchronize functions, but there are also other posts which caution against closure callbacks because of the potential to inadvertently retain objects and cause memory issues.
Assume inside a custom view controller is a function, foo, that uses the Bar class to get data from the server.
class CustomViewController : UIViewController {
function foo() {
// Do other stuff
// Use Bar to get data from server
Bar.getServerData()
}
}
Option 1: Define getServerData to accept a callback. Define the callback as a closure inside CustomViewController.
Option 2: Use NSNotifications instead of a callback. Inside of getServerData, post a NSNotification when the server returns data, and ensure CustomViewController is registered for the notification.
Option 1 seems desirable for all the reasons people caution against NSNotification (e.g., compiler checks, traceability), but doesn't using a callback create a potential issue where CustomViewController is unnecessarily retained and therefore potentially creating memory issues?
If so, is the right way to mitigate the risk by using a callback, but not using a closure? In other words, define a function inside CustomViewController with a signature matching the getServerData callback, and pass the pointer to this function to getServerData?
I'm always going with Option 1 you just need to remember of using [weak self] or whatever you need to 'weakify' in order to avoid memory problems.
Real world example:
filterRepository.getFiltersForType(filterType) { [weak self] (categories) in
guard let strongSelf = self, categories = categories else { return }
strongSelf.dataSource = categories
strongSelf.filteredDataSource = strongSelf.dataSource
strongSelf.tableView?.reloadData()
}
So in this example you can see that I pass reference to self to the completion closure, but as weak reference. Then I'm checking if the object still exists - if it wasn't released already, using guard statement and unwrapping weak value.
Definition of network call with completion closure:
class func getFiltersForType(type: FilterType, callback: ([FilterCategory]?) -> ()) {
connection.getFiltersCategories(type.id).response { (json, error) in
if let data = json {
callback(data.arrayValue.map { FilterCategory(attributes: $0) } )
} else {
callback(nil)
}
}
}
I'm standing for closures in that case. To avoid unnecessary retains you just need to ensure closure has proper capture list defined.
I've been reading a bunch about Swift initilization lately, and one solution that appears to have some merit is utilizing lazy variables to avoid the doom and gloom of optionals, especially when extending UIViewControllers or other classes along those lines. With that in mind, I've got code that looks like this:
final class MyViewController : UIViewController {
lazy private var myOtherViewController: MyOtherViewController = MyOtherViewController()
deinit {
// myOtherViewController = nil // Can't do this. Expression resolves to an unused l-value
}
override func viewDidLoad() {
super.viewDidLoad()
myOtherViewController.foo();
}
}
// elsewhere...
final class MyOtherViewController : UIViewController {
deinit {
print("Deinit!")
}
}
In the example here it appears that MyOtherViewController's deinit method never seems to fire, but I also have no way to make myOtherViewController deinit. Setting it to nil isn't allowed. Is there something I'm missing that forces MyOtherViewController to retain? Or have I just been impatient with the garbage collector?
To do this, your lazy variable would have to be declared as optional even though you intend to initialize it as soon as the value is needed (i.e. lazily).
class MyObject {
func run() {
print( "MyObject :: run()" )
}
init() {
print( "MyObject :: init" )
}
deinit {
print( "MyObject :: deinit" )
}
}
class MyContext {
lazy var myObject:MyObject? = MyObject()
}
let myContext = MyContext()
myContext.myObject?.run() //< "MyObject :: init"
myContext.myObject = nil //< "MyObject :: deinit"
Also, I disagree with the notion of the "doom and gloom of optionals"—one only need know which of the many available techniques is most convenient and practical way handle them, and how to avoid allowing too many permutations of state to exist among combinations of optional and non-optional values in a given context. Furthermore, an optional is actually exactly what you want here because you intend to nullify it. Employing an optional doesn't mean that a value will be nil for now until you initialize it, but rather that it may be nil at any point in its life, even if it is defined at declaration or any other time beforehand. If avoiding optionals is truly that high of a priority for you, you'd have to take a step back and re-evaluate your architecture to create a situation where you no longer have the need to de-initialize the value.
I agree with Grimxn, that this pattern of setting that property to nil (and thus needing to make it optional in order to be able to do that) is unnecessary. When MyViewController is deallocated, it automatically releases its strong reference to MyOtherViewController.
The only time you need to manually nil this property is when you have to resolve a strong reference cycle (and if you had such cycle, you can't resolve that in deinit, but rather viewDidDisappear or something like that).
If you're not seeing this other view controller get deallocated, then I'd suggest finding the source of the strong reference cycle and resolving that.