iOS + React Native - memory leaks - ios

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()
}

Related

Memory Leak Kotlin Native library in iOS

I'm building a Kotlin library to use in my iOS app using Kotlin/Native. After I call some methods in the library from Swift, which works, I also want to call methods in Swift from the library. To accomplish this I implemented an interface in the library:
class Outbound {
interface HostInterfaceForTracking {
fun calcFeatureVector(bitmap: Any?): Array<Array<FloatArray>>?
}
var hostInterface: HostInterfaceForTracking? = null
fun registerInterface(hostInterface: HostInterfaceForTracking) {
this.hostInterface = hostInterface
instance.hostInterface = hostInterface
}
}
This is implemented on the Swift side like this:
class HostInterfaceForTracking : OutboundHostInterfaceForTracking {
var t : Outbound? = nil
init() {
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
}
func calcFeatureVector(bitmap: Any?) -> KotlinArray<KotlinArray<KotlinFloatArray>>? {
do {
var test : Any? = (bitmap as! Bitmap).bitmap
return nil
} catch {
return nil
}
}
}
The TrackingWrapper looks like this:
class TrackingWrapper : NSObject {
static var instance: TrackingWrapper? = nil
var inbound: Inbound? = nil
var worker: Worker
override init() {
self.worker = Worker()
super.init()
initInboundInterface()
}
func initInboundInterface() {
runOnMatchingLibraryThread {
TrackingWrapper.instance = self
self.inbound = Inbound()
HostInterfaceForTracking()
}
}
func runOnMatchingLibraryThread(block: #escaping() -> Void) {
worker.enqueue {
block()
}
}
}
The function runOnMatchingLibraryThread is needed because every call to the TrackingLibrary needs to be called from the exact same thread, so the Worker class initializes a thread and enqueues every method to that thread.
The Bitmap in this case is simply a wrapper for an UIImage, which I already accessed with the .bitmap call, so I've tried to access the wrapped UIImage and save it in the test variable. The library gets the current camera frame from the Swift side every few frames and sends the current image wrapped as a Bitmap to the method calcFeatureVector depicted here.
Problem: My memory load starts increasing as soon as the app starts until the point it crashes. This is not the case if I don't access the wrapped UIImage (var test : Any? = (bitmap as! Bitmap)). So there is a huge memory leak, just by accessing the wrapped variable on the Swift side. Is there anything I've missed or is there any way to release the memory?
Looks like you have a circular dependency here:
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
You are asking a property inside HostInterfaceForTracking to maintain a strong reference to the same instance of HostInterfaceForTracking. You should be using [weak self] to avoid the circular reference.
EDIT:
Ok after seeing the rest of you code theres a lot to unpack. There is a lot of unnecessary bouncing back and forth between classes, functions and threads.
There is no need to use runOnMatchingLibraryThread to just create an instance of something. You only need to use that for the code processing the image itself (I would assume, I haven't seen anything so far that requires being split off into another thread). Inside TrackingWrapper, you can create a singleton more easily, and matching the swift pattern by simply doing this as the first line:
static let shared = TrackingWrapper()
And everywhere you want to use it, you can just call TrackingWrapper.shared. This is more common and will avoid one of the levels of indirection in the code.
I'm not sure what Worker or Inbound are, but again these can and should be created inside the TrackingWrapper init, rather than branching Inbound's init, to use another thread.
Inside initInboundInterface you are creating an instance of HostInterfaceForTracking() which doesn't get stored anywhere. The only reason HostInterfaceForTracking is continuing to stay in memory after its creation, is because of the internal circular dependency inside it. This is 100% causing some form of a memory issue for you. This should probably also be a property on TrackingWrapper, and again, its Init should not be called inside runOnMatchingLibraryThread.
Having HostInterfaceForTracking's init, also using runOnMatchingLibraryThread is problematic. If we inline all the code whats happening is this:
TrackingWrapper
init() {
self.runOnMatchingLibraryThread {
TrackingWrapper.instance = self
self.inbound = Inbound()
TrackingWrapper.instance?.runOnMatchingLibraryThread {
self.t = Outbound()
self.t!.registerInterface(hostInterface: self)
}
}
}
Having all these classes unnecessarily keep coming back to TrackingWrapper is going to cause issues.
Inside HostInterfaceForTracking 's init, no need to be creating Outbound on a separate thread. First line in this class can simply be:
var t : Outbound = OutBound()
Or do it in the init if you prefer. Either way will also remove the issue of needing to unwrap Outbound before using it.
Inside Outbound you are storing 2 references to the hostInterface instance:
this.hostInterface = hostInterface
instance.hostInterface = hostInterface
I would have imagined there should only be 1. If there are now multiple copies of a class that has a circular dependency, which has multiple calls to separate threads. This again will cause issues.
I'm still not sure on the differences between Swift and Kotlin. In Swift when passing self into a function to be stored, the class storing it would mark the property as weak, like so:
weak var hostInterface: ......
Which will avoid any circular dependency from forming. A quick google says this isn't how things work in Kotlin. It might be better to look into the swift side passing in a closure (lambda on kotlin) and the kotlin side executing that. This might avoid the need to store a strong reference. Otherwise you need to be looking into some part of your code setting hostInterface back to null. Again its a bit hard to say only seeing some of the code and not knowing how its working.
In short, it looks like the code is very over complicated, and needs to be simplified, so that all these moving pieces can be tracked easier.

Should an asynchronous swift function retain a strong reference to the object?

We implemented and extension to NSData that asynchronously persists the data to a URL.
Here is a short version of the function.
extension NSData {
func writeToURL1(url:NSURL, completion: () -> Void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { [weak self] in
guard let strongSelf = self else { return }
strongSelf.writeToURL(url, atomically: true)
completion()
})
}
}
Here is how we use it:
var imageData = UIImageJPEGRepresentation(image, 0.8)
imageData?.writeToURL(someURL) { in ... }
The problem of course is if imageData gets deallocated before the write operation is completed strongSelf will be nil and the completion handler will never be called.
There are two solutions to that problem.
remove [weak self] (i.e. have a strong reference to self in writeToURL1.
reference imageData in the completion block (i.e. imageData?.writeToURL(someURL) { in imageData = nil ... })
What approach is more Swift friendly and what approach should we choose?
Thank you!
You should use a strong reference if you don't want the object to go away from under your feet (and doing so wouldn't create a reference cycle); a weak reference if you don't care if the object goes away from under your feet; an unowned reference if you need the object to be around, and have a strong guarantee that the object won't go away from under your feet, but a strong reference would create a cycle.
In your case, you care that the object might go away, because that means that you won't be able to save it. As you have no guarantee that something else will keep the object alive until that task is completed, you should use a strong reference.
Strong references to self in closures are a problem when you carry the closure around because it's easy to end up with a non-obvious reference cycle, but you know for a fact that the reference will be dropped right after the closure is executed, so it's not a problem here.
It sounds like you just want to strongly capture the reference to the NSData object, so removing the [weak self] is the easiest and best approach in my opinion. Usually, weak references are used to avoid retain cycles when capturing in a closure. However, you're not actually creating a retain cycle, simply a one way retain by capturing self in the block. The block is not retained by self, it's simply passed down the call stack into dispatch_async, where it is ultimately invoked and deallocated. So there is no retain cycle to avoid by using weak self, you just have a retain occur via the closure which is desirable. That is, you want to keep the data in memory until that closure is invoked.

How is a strong retain cycle possible with async or static calls?

I am trying to grasp how I can recognize when a strong retain cycle is possible and requires me to use [weak/unowned self]. I've been burned by unnecessarily using [weak/unowned self] and the self was deallocated immediately before giving me a chance to use it.
For example, below is an async network call that refers to self in the closure. Can a memory leak happen here since the network call is made without storing the call it self into a variable?
NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: url)!) {
(data, response, error) in
self.data = data
)
Here's another example using the NSNotificationCenter, where a call can be made later asynchronously:
NSNotificationCenter.defaultCenter().addObserverForName(
UIApplicationSignificantTimeChangeNotification, object: nil, queue: nil) {
[unowned self] _ in
self.refresh()
}
My question is in what cases is a strong retain cycle possible? If I am making an asynchronous call or static call that references self in a closure, does that make it a candidate for [weak/unowned self]? Thanks for shedding any light on this.
A retain cycle is a situation when two objects has a strong reference to each other.
You are working with static variables NSURLSession.sharedSession() & NSNotificationCenter.defaultCenter() and as you may remember:
A singleton object provides a global point of access to the resources
of its class...You obtain the global instance from a singleton class
through a factory method. The class lazily creates its sole instance
the first time it is requested and thereafter ensures that no other
instance can be created. A singleton class also prevents callers from
copying, retaining, or releasing the instance.
https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Singleton.html
Your "self" instance (like the others) doesn't have a strong reference to singletons objects and its closures too, that's why you don't have to worry about retain cycle in your case.
Check this great article for more details:
https://digitalleaves.com/blog/2015/05/demystifying-retain-cycles-in-arc/
In a nutshell:
The retain cycle can happen in two cases.
Case 1:
When two instances hold a strong reference to each other. You have to solve this by marking one of them as weak.
Case 2: (Which is related to your questions)
If you assign a closure to a property of a class instance and the body of that closure captures the instance.
In your two examples, no need to use weak self at all as NSNotificationCenter nor NSURLSession are properties to your class instance. (Or in other meaning, you don't have strong references to them)
Check this example where I have to use weak self:
[self.mm_drawerController setDrawerVisualStateBlock:^(MMDrawerController *drawerController, MMDrawerSide drawerSide, CGFloat percentVisible) {
if (drawerSide == MMDrawerSideRight && percentVisible == 1.0) {
[weakself showOverlayBgWithCloseButton:YES];
}
else{
[weakself hideOverlayBg];
}
}];
I have a strong reference to mm_drawerController and I assign a closure to it right?. inside this closure I want to capture self. So the closure will have a strong reference to self !! which is a disaster. In that case you will have a retain cycle. To break this cycle, use weak self inside the closure.

How memory leak will occur in swift?

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.

Swift ARC and blocks

I'm trying a simple example as seen here:
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-XID_88
And this is my code. (Ignore other possible code, this is a empty project with this code written inside an empty UIViewcontroller viewDidLoad)
dispatch_async(dispatch_get_main_queue()) {
[unowned self] in
println(self)
}
I don't understand why it crashes when I run the pro
thread #1: tid = 0x1a796, 0x00284d18 libswiftCore.dylib`_swift_release_slow + 8, queue =
'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1,
address=0x458bc681)
Did something changed on the latest beta(5) and this is not supported anymore?
Thanks
edit:
Interesting that this code works on Objc
__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#", weakSelf);
});
edit2:
The explanation on this link : Shall we always use [unowned self] inside closure in Swift on the difference of weak and unowned is wrong.
It's not just that weak nils and unowned doesn't. If that's the case, this should crash as well:
dispatch_async(dispatch_get_main_queue()) {
[weak self] in
println(self)
}
but it doesn't, and it prints the pointer, so, it's not nil.
[Unowned self] makes it so the closure does not create a strong reference to self and it does not automatically set it to nil if it gets deallocated either. By the time the async method is executed, self has been deallocated. That is why you are getting the crash.
It certainly doesn't make sense to use unowned in a one time asynchronous call. It would be better to capture a strong reference to it to be sure it sticks around. There still won't be a strong reference cycle because self does not own the closure.
Side Note: This cannot be all of your code as self isn't defined anywhere in your code.
unowned and weak are two different things. In Objective-C, unowned is called unsafe unretained. You can use weak in both languages. weak means that the runtime will automatically convert the reference to nil if the object is deallocated. unowned or unsafe unretained means that it will not be set to nil for you (which is why it is called "unsafe" in Objective-C.
Unowned should only ever be used in circumstances where the object will never be deallocated. In those circumstances, use weak.
Keep in mind, that if you capture a variable as weak in Swift, the reference will be made an optional so to use it you will have to unwrap it:
dispatch_async(dispatch_get_main_queue()) {
[weak self] in
if let actualSelf == self {
// do something with actualSelf
}
// you can still print the "wrapped" self because it is fine to print optionals
// even if they are `nil`
println(self)
}
But to be clear, it would still be best to use a strong reference in this circumstance:
dispatch_async(dispatch_get_main_queue()) {
println(self)
}

Resources