{"id":13908014,"url":"https://github.com/malcommac/Repeat","last_synced_at":"2025-07-18T06:32:17.686Z","repository":{"id":40652038,"uuid":"122378997","full_name":"malcommac/Repeat","owner":"malcommac","description":"🕦 Modern Timer in Swift, Debouncer and Throttler (alternative to NSTimer) made with GCD","archived":false,"fork":false,"pushed_at":"2021-09-08T15:54:14.000Z","size":183,"stargazers_count":1466,"open_issues_count":14,"forks_count":91,"subscribers_count":20,"default_branch":"develop","last_synced_at":"2024-11-21T13:03:50.604Z","etag":null,"topics":["debounce","gcd","grand-central-dispatch","nstimer","throttler","timer"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/malcommac.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-21T18:54:59.000Z","updated_at":"2024-11-11T13:36:30.000Z","dependencies_parsed_at":"2022-08-27T01:42:31.209Z","dependency_job_id":null,"html_url":"https://github.com/malcommac/Repeat","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FRepeat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FRepeat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FRepeat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malcommac%2FRepeat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/malcommac","download_url":"https://codeload.github.com/malcommac/Repeat/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226361634,"owners_count":17612933,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["debounce","gcd","grand-central-dispatch","nstimer","throttler","timer"],"created_at":"2024-08-06T23:02:24.681Z","updated_at":"2024-11-25T16:31:19.819Z","avatar_url":"https://github.com/malcommac.png","language":"Swift","readme":"# Repeat - modern NSTimer in GCD, debouncer and throttler\n\n[![Version](https://img.shields.io/cocoapods/v/Repeat.svg?style=flat)](http://cocoadocs.org/docsets/Repeat) [![License](https://img.shields.io/cocoapods/l/Repeat.svg?style=flat)](http://cocoadocs.org/docsets/Repeat) [![Platform](https://img.shields.io/cocoapods/p/Repeat.svg?style=flat)](http://cocoadocs.org/docsets/Repeat)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/Repeat.svg)](https://img.shields.io/cocoapods/v/Repeat.svg)\n[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n[![Twitter](https://img.shields.io/badge/twitter-@danielemargutti-blue.svg?style=flat)](http://twitter.com/danielemargutti)\n\n\u003cp align=\"center\" \u003e★★ \u003cb\u003eStar me to follow the project! \u003c/b\u003e ★★\u003cbr\u003e\nCreated by \u003cb\u003eDaniele Margutti\u003c/b\u003e - \u003ca href=\"http://www.danielemargutti.com\"\u003edanielemargutti.com\u003c/a\u003e\n\u003c/p\u003e\n\n\nRepeat is small lightweight alternative to `NSTimer` with a modern Swift Syntax, no strong references, multiple observers reusable instances.\nRepeat is based upon GCD - Grand Central Dispatch. \nIt also support debouncer and throttler features.\n\n## A deep look at Timers\n\nIf you want to learn more about it check out my article on Medium: [**\"The secret world of NSTimer\"**](https://medium.com/@danielemargutti/the-secret-world-of-nstimer-708f508c9eb).\n\n## Features Highlights\n\nMain features offered by Repeat are:\n\n* **Simple, less verbose APIs** methods to create and manage our timer. Just call `every()` or `once` to create a new Timer even in background thread.\n* **Avoid strong references** to the destination target and avoid NSObject inheritance.\n* Support **multiple observers** to receive fire events from timer.\n* Ability to **pause , start , resume and reset** our timer without allocating a new instance.\n* Ability to set **different repeat modes** (`infinite` : infinite sequence of fires, at regular intervals, `finite` : a finite sequence of fires, at regular intervals, `once` : a single fire events at specified interval since start).\n\nMoreover Repeat also provide supports for:\n\n* **Debouncer**: Debouncer will delay a function call, and every time it's getting called it will delay the preceding call until the delay time is over.\n* **Throttler**: Throttling wraps a block of code with throttling logic, guaranteeing that an action will never be called more than once each specified interval.\n\n## Other Libraries You May Like\n\nI'm also working on several other projects you may like.\nTake a look below:\n\n\u003cp align=\"center\" \u003e\n\n| Library         | Description                                      |\n|-----------------|--------------------------------------------------|\n| [**SwiftDate**](https://github.com/malcommac/SwiftDate)       | The best way to manage date/timezones in Swift   |\n| [**Hydra**](https://github.com/malcommac/Hydra)           | Write better async code: async/await \u0026 promises  |\n| [**Flow**](https://github.com/malcommac/Flow) | A new declarative approach to table managment. Forget datasource \u0026 delegates. |\n| [**SwiftRichString**](https://github.com/malcommac/SwiftRichString) | Elegant \u0026 Painless NSAttributedString in Swift   |\n| [**SwiftLocation**](https://github.com/malcommac/SwiftLocation)   | Efficient location manager                       |\n| [**SwiftMsgPack**](https://github.com/malcommac/SwiftMsgPack)    | Fast/efficient msgPack encoder/decoder           |\n\u003c/p\u003e\n\n## Documentation\n* [Timer](#timer)\n* [Debouncer](#debouncer)\n* [Throttler](#throttler)\n\n\u003ca name=\"timer\"/\u003e\n\n### Timer\n\n**Note**: As any other object `Repeater` class is subject to the standard memory management rules. So once you create your timer instance you need to retain it somewhere in order to avoid premature deallocation just after the start command.\n\n#### Create single fire timer\n\nThe following code create a timer which fires a single time after 5 seconds.\n\n```swift\nself.timer = Repeater.once(after: .seconds(5)) { timer in\n  // do something\t\n}\n```\n\n#### Create recurrent finite timer\n\nThe following code create a recurrent timer: it will fire every 10 minutes for 5 times, then stops.\n\n```swift\nself.timer = Repeater.every(.minutes(10), count: 5) { timer  in\n  // do something\t\t\n}\n```\n\n#### Create recurrent infinite timer\n\nThe following code create a recurrent timer which fires every hour until it is manually stopped .\n\n```swift\nself.timer = Repeater.every(.hours(1)) { timer in\n  // do something\n}\n```\n\n#### Manage a timer\n\nYou can create a new instance of timer and start as needed by calling the `start()` function.\n\n```swift\nself.timer = Repeater(interval: .seconds(5), mode: .infinite) { _ in\n  // do something\t\t\n}\ntimer.start()\n```\n\nOther functions are:\n\n* `start()`: start a paused or newly created timer\n* `pause()`: pause a running timer\n* `reset(_ interval: Interval, restart: Bool)`: reset a running timer, change the interval and restart again if set.\n* `fire()`: manually fire an event of the timer from an external source\n\nProperties:\n\n* `.id`: unique identifier of the timer\n* `.mode`: define the type of timer (`infinite`,`finite`,`once`)\n* `.remainingIterations`: for a `.finite` mode it contains the remaining number of iterations before it finishes.\n\n#### Adding/Removing Observers\n\nBy default a new timer has a single observer specified by the init functions. You can, however, create additional observer by using `observe()` function. The result of this call is a token identifier you can use to remove the observer in a second time.\nTimer instance received in callback is weak.\n\n```swift\nlet token = timer.observe { _ in\n  // a new observer is called\t\t\n}\ntimer.start()\n```\n\nYou can remove an observer by using the token:\n\n```swift \ntimer.remove(token)\n```\n\n#### Observing state change\n\nEach timer can be in one of the following states, you can observe via `.state` property:\n\n* `.paused`: timer is in idle (never started yet) or paused\n* `.running`: timer is currently active and running\n* `.executing`: registered observers are being executed\n* `.finished`: timer lifecycle is finished (it's valid for a finite/once state timer)\n\nYou can listen for state change by assigning a function callback for `.onStateChanged` property.\n\n```swift\ntimer.onStateChanged = { (timer,newState) in\n\t// your own code\n}\n```\n\u003ca name=\"debouncer\"/\u003e\n\n### Debouncer\n\nSince 0.5 Repeater introduced `Debouncer` class.\nThe Debouncer will delay a function call, and every time it's getting called it will delay the preceding call until the delay time is over.\n\nThe debounce function is an extremely useful tool that can help throttle requests.\nIt is different to throttle though as throttle will allow only one request per time period, debounce will not fire immediately and wait the specified time period before firing the request.\nIf there is another request made before the end of the time period then we restart the count. This can be extremely useful for calling functions that often get called and are only needed to run once after all the changes have been made.\n\n```swift\nlet debouncer = Debouncer(.seconds(10))\ndebouncer.callback = {\n\t// your code here\n}\n\n// Call debouncer to start the callback after the delayed time.\n// Multiple calls will ignore the older calls and overwrite the firing time.\ndebouncer.call()\n```\n\n(Make sure to check out the Unit Tests for further code samples.)\n\n\u003ca name=\"throttler\"/\u003e\n\n### Throttler\n\nSince 0.5 Repeater introduced `Throttler` class.\n\nThrottling wraps a block of code with throttling logic, guaranteeing that an action will never be called more than once each specified interval. Only the last dispatched code-block will be executed when delay has passed.\n\n```swift\nlet throttler = Throttler(time: .milliseconds(500), {\n  // your code here\n})\n\n// Call throttler. Defined block will never be called more than once each specified interval.\nthrottler.call()\n```\n\n## Requirements\n\nRepeat is compatible with Swift 4.x.\nAll Apple platforms are supported:\n\n* iOS 8.0+\n* macOS 10.10+\n* watchOS 2.0+\n* tvOS 9.0+\n\n## Latest Version\n\nLatest version of Repeat is [0.5.4](https://github.com/malcommac/Repeat/releases/tag/0.5.4) published on 2018/04/28.\nFull changelog is available in [CHANGELOG.md](CHANGELOG.md) file.\n\n## Installation\n\n\u003ca name=\"cocoapods\" /\u003e\n\n### Install via CocoaPods\n\n[CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like Repeat in your projects. You can install it with the following command:\n\n```bash\n$ sudo gem install cocoapods\n```\n\n\u003e CocoaPods 1.0.1+ is required to build Repeat.\n\n#### Install via Podfile\n\nTo integrate Repeat into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\nsource 'https://github.com/CocoaPods/Specs.git'\nplatform :ios, '8.0'\n\ntarget 'TargetName' do\nuse_frameworks!\npod 'Repeat'\nend\n```\n\nThen, run the following command:\n\n```bash\n$ pod install\n```\n\n\u003ca name=\"carthage\" /\u003e\n\n### Carthage\n\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.\n\nYou can install Carthage with [Homebrew](http://brew.sh/) using the following command:\n\n```bash\n$ brew update\n$ brew install carthage\n```\n\nTo integrate Repeat into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"malcommac/Repeat\"\n```\n\nRun `carthage` to build the framework and drag the built `Repeat.framework` into your Xcode project.\n\n\n","funding_links":[],"categories":["HarmonyOS","Swift"],"sub_categories":["Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalcommac%2FRepeat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalcommac%2FRepeat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalcommac%2FRepeat/lists"}