Giter Club home page Giter Club logo

Comments (12)

MrPans avatar MrPans commented on May 16, 2024

the test step could expose memory leak are as follow:

  1. We have two ViewController embed in UINavigationController: ViewControllerA and ViewControllerB
  2. push to ViewControllerB
  3. use Each like demo doing, at ViewControllerB's viewDidLoad function.
    override func viewDidLoad() {
        super.viewDidLoad()
        Each(1).seconds.perform {
            print("second passed")
            return false
        }
    }
  1. Pop ViewControllerB.
  2. Timer is still running, because of the each instance wasn't free and deInit not been called.
  3. We got a memory leak.

from each.

dalu93 avatar dalu93 commented on May 16, 2024

For now, a simple workaround could be: store the Each instance in your UIViewController and call the stop() method in the deinit as below:

class BViewController: UIViewController {

    let timer = Each(1).seconds

    deinit {
        timer.stop()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        timer.perform { [weak self] in
            print("Timer called")
            self?.dismiss(animated: true, completion: nil)
            return .continue
        }
    }
}

from each.

MrPans avatar MrPans commented on May 16, 2024

Here is a way to resolve this issue in Objective-C: PSWeakProxy
But invoke it case dependence.

I'm trying to find out a way with pure swift.

from each.

dalu93 avatar dalu93 commented on May 16, 2024

@DeveloperPans I'm actually working on it on feature/memory-leak-fix branch

For now I succeeded to make a sort of weak timer. The only requirement is that the object has to hold a strong reference to the Each instance, like the example below:

class BVC: UIViewController {

    let timer = Each(1).seconds

    override func viewDidLoad() {
        super.viewDidLoad()

        timer.perform {
            print("tiemer called")
            return .continue
        }
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        self.dismiss(animated: true, completion: nil)
    }
}

This works nicely and there is no need to call the stop() when the BVC.deinit is called

from each.

MrPans avatar MrPans commented on May 16, 2024

great!

from each.

dalu93 avatar dalu93 commented on May 16, 2024

So, as I explained in the post up here, with this fix, you are not able anymore to create a timer in your method scope by only typing the simple syntax (see below) because the controller has to keep a reference to it.

Each(1).seconds.perform {
    // do something
    return .continue 
}

I found an another solution with a colleague of mine, which allows you to do it again. But Each needs the owner reference to check whether it's been deallocated in the mean time to stop the timer execution, so a prototype of the implementation will be

Each(1).seconds.performOn(self) {
    // do something
    return .continue
}

What do you think guys? I can even try to wrap this method call up in a NSObject extension.

from each.

dalu93 avatar dalu93 commented on May 16, 2024

Actually I'm thinking about this issue really a lot. I decided that the memory leak should stay there: unfortunately it's the default behavior of NSTimer class provided by Apple. There are some workarounds to keep your code free from memory leaks using Each

Workaround 1

In case you don't want to declare a property that holds the Each reference, create a normal Each timer in your method scope and return .stop/true whenever the owner instance is nil

Each(1).seconds.perform { [weak self] in
    guard let _ = self else { return .stop }

    print("timer called")
    return .continue
}

90% of closures will call self somehow, so this isn't so bad

Workaround 2

In case the first workaround wasn't enough, you can declare a property that holds the Each reference and call the stop() function whenever the owner is deallocated

final class ViewController: UIViewController {
    private let _timer = Each(1).seconds

    deinit {
        _timer.stop()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        _timer.perform {
            // do something and return. you can check here if the `self` instance is nil as for workaround #1
        }
    }
}

@DeveloperPans I'll update the README with these examples

from each.

MrPans avatar MrPans commented on May 16, 2024

May be paste Workaround 2 to README could help more people and this discuss perform its values. Do you think so?

from each.

dalu93 avatar dalu93 commented on May 16, 2024

I think for now it's ok until someone will find a good solution for it.
Each is cool because the developer can simply use it. All the fixes I found make the interface not easy as it is now.

from each.

MrPans avatar MrPans commented on May 16, 2024

Less global variables are better… I think.

So I vote performOn: )
Best regards!


潘晟
Shawn Pan
Team Leader
http://shengpan.net

在 2016年10月24日,21:26,dalu93 [email protected] 写道:

So, as I explained in the post up here, with this fix, you are not able anymore to create a timer in your method scope by only typing because the controller has to keep a reference to it.

Each(1).seconds.perform {
// do something
return .continue
}
I found an another solution with a colleague of mine, which allows you to do it again. But Each needs the owner reference to check whether it's been deallocated in the mean time to stop the timer execution, so a prototype of the implementation will be

Each(1).seconds.performOn(self) {
// do something
return .continue
}
What do you think guys? I can even try to wrap up this method call in a NSObject extension.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub #4 (comment), or mute the thread https://github.com/notifications/unsubscribe-auth/AIgE4MHXZT8c3zzf2cS0_cfewIORtpYYks5q3LH1gaJpZM4Kd7Kf.

from each.

dalu93 avatar dalu93 commented on May 16, 2024

I'm gonna implement that method too. In this way the developer can easily choose his implementation @DeveloperPans

from each.

dalu93 avatar dalu93 commented on May 16, 2024

I just merged the new method on develop. It will be released soon in the version 1.1.1

from each.

Related Issues (9)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.