Giter VIP home page Giter VIP logo

repeat's Introduction

Repeat - modern NSTimer in GCD, debouncer and throttler

Version License Platform CocoaPods Compatible Carthage Compatible Twitter

★★ Star me to follow the project! ★★
Created by Daniele Margutti - danielemargutti.com

Repeat is small lightweight alternative to NSTimer with a modern Swift Syntax, no strong references, multiple observers reusable instances. Repeat is based upon GCD - Grand Central Dispatch. It also support debouncer and throttler features.

A deep look at Timers

If you want to learn more about it check out my article on Medium: "The secret world of NSTimer".

Features Highlights

Main features offered by Repeat are:

  • 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.
  • Avoid strong references to the destination target and avoid NSObject inheritance.
  • Support multiple observers to receive fire events from timer.
  • Ability to pause , start , resume and reset our timer without allocating a new instance.
  • 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).

Moreover Repeat also provide supports for:

  • 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.
  • Throttler: Throttling wraps a block of code with throttling logic, guaranteeing that an action will never be called more than once each specified interval.

Other Libraries You May Like

I'm also working on several other projects you may like. Take a look below:

Library Description
SwiftDate The best way to manage date/timezones in Swift
Hydra Write better async code: async/await & promises
Flow A new declarative approach to table managment. Forget datasource & delegates.
SwiftRichString Elegant & Painless NSAttributedString in Swift
SwiftLocation Efficient location manager
SwiftMsgPack Fast/efficient msgPack encoder/decoder

Documentation

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.

Create single fire timer

The following code create a timer which fires a single time after 5 seconds.

self.timer = Repeater.once(after: .seconds(5)) { timer in
  // do something	
}

Create recurrent finite timer

The following code create a recurrent timer: it will fire every 10 minutes for 5 times, then stops.

self.timer = Repeater.every(.minutes(10), count: 5) { timer  in
  // do something		
}

Create recurrent infinite timer

The following code create a recurrent timer which fires every hour until it is manually stopped .

self.timer = Repeater.every(.hours(1)) { timer in
  // do something
}

Manage a timer

You can create a new instance of timer and start as needed by calling the start() function.

self.timer = Repeater(interval: .seconds(5), mode: .infinite) { _ in
  // do something		
}
timer.start()

Other functions are:

  • start(): start a paused or newly created timer
  • pause(): pause a running timer
  • reset(_ interval: Interval, restart: Bool): reset a running timer, change the interval and restart again if set.
  • fire(): manually fire an event of the timer from an external source

Properties:

  • .id: unique identifier of the timer
  • .mode: define the type of timer (infinite,finite,once)
  • .remainingIterations: for a .finite mode it contains the remaining number of iterations before it finishes.

Adding/Removing Observers

By 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. Timer instance received in callback is weak.

let token = timer.observe { _ in
  // a new observer is called		
}
timer.start()

You can remove an observer by using the token:

timer.remove(token)

Observing state change

Each timer can be in one of the following states, you can observe via .state property:

  • .paused: timer is in idle (never started yet) or paused
  • .running: timer is currently active and running
  • .executing: registered observers are being executed
  • .finished: timer lifecycle is finished (it's valid for a finite/once state timer)

You can listen for state change by assigning a function callback for .onStateChanged property.

timer.onStateChanged = { (timer,newState) in
	// your own code
}

Since 0.5 Repeater introduced Debouncer class. The 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.

The debounce function is an extremely useful tool that can help throttle requests. It 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. If 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.

let debouncer = Debouncer(.seconds(10))
debouncer.callback = {
	// your code here
}

// Call debouncer to start the callback after the delayed time.
// Multiple calls will ignore the older calls and overwrite the firing time.
debouncer.call()

(Make sure to check out the Unit Tests for further code samples.)

Since 0.5 Repeater introduced Throttler class.

Throttling 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.

let throttler = Throttler(time: .milliseconds(500), {
  // your code here
})

// Call throttler. Defined block will never be called more than once each specified interval.
throttler.call()

Requirements

Repeat is compatible with Swift 4.x. All Apple platforms are supported:

  • iOS 8.0+
  • macOS 10.10+
  • watchOS 2.0+
  • tvOS 9.0+

Latest Version

Latest version of Repeat is 0.5.4 published on 2018/04/28. Full changelog is available in CHANGELOG.md file.

Installation

CocoaPods 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:

$ sudo gem install cocoapods

CocoaPods 1.0.1+ is required to build Repeat.

Install via Podfile

To integrate Repeat into your Xcode project using CocoaPods, specify it in your Podfile:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'

target 'TargetName' do
use_frameworks!
pod 'Repeat'
end

Then, run the following command:

$ pod install

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate Repeat into your Xcode project using Carthage, specify it in your Cartfile:

github "malcommac/Repeat"

Run carthage to build the framework and drag the built Repeat.framework into your Xcode project.

repeat's People

Contributors

arielelkin avatar christiansteffens avatar elud avatar fiveze avatar imokhles avatar malcommac avatar nemesis avatar palmtrae avatar philium avatar rockerhx avatar t-pham avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

repeat's Issues

Repeat.Interval.* causing a crash on iOS 9 device

Initializing a Repeat.Interval using Repeat.Interval.* (example: Repeat.Interval.nanoseconds(100)) causes a fatal crash on an iOS 9 device.

The same line of code works without a problem on an iOS 12 device.

Could it have to do with DispatchTimeInterval? I am unsure

Error installing Repeat with CocoaPods

I am using CocoaPods 1.1.1 and got this error when attempting to pod install Repeat:

warning: --depth is ignored in local clones; use file:// instead.
warning: Could not find remote branch 0.1.0 to clone.
fatal: Remote branch 0.1.0 not found in upstream origin
fatal: The remote end hung up unexpectedly

Since this appears to be your initial release, I think this might be the solution:
https://stackoverflow.com/a/37038760/133485

Thanks for what looks to be a great timer!

About the timer release collapse

/// Destroy current timer
private func destroyTimer() {
self.timer?.setEventHandler(handler: nil)
self.timer?.cancel()

	if state == .paused || state == .finished {
		self.timer?.resume()
	}
}

This method when the order is written is wrong, the timer if is put up, is to call self. The timer?resume (), and then call the self. The timer?.cancel () in the self. The timer = nil to release,Or it will collapse

Should torelance property be tolerance?

The comment seems to indicate this but it seems misspelled for the parameter and property, etc.

	/// Initialize a new timer.
	///
	/// - Parameters:
	///   - interval: interval of the timer
	///   - mode: mode of the timer
	///   - torelance: tolerance of the timer, 0 is default.
	///   - queue: queue in which the timer should be executed; if `nil` a new queue is created automatically.
	///   - observer: observer
	public init(interval: Interval, mode: Mode = .infinite,
				torelance: DispatchTimeInterval = .nanoseconds(0),
				queue: DispatchQueue? = nil,
				observer: @escaping  Observer) {
		self.mode = mode
		self.interval = interval
		self.torelance = torelance
		self.countRemainingRepeat = mode.repeatCount
		self.queue = (queue ?? DispatchQueue(label: "com.repeat.queue"))
		self.timer = configureTimer()
		self.observe(observer)
	}

Crashes from time to time on debouncer

It happens unexpectedly from time to time on background and on foreground.
iOS 12 and iOS 13 on different iPhones versions.

3  Repeat                         0x10330c760 $s6Repeat8RepeaterC5reset_7restartyAC8IntervalOSg_SbtF + 196
4  Repeat                         0x10330a864 $s6Repeat9DebouncerC4call8newDelayyAA8RepeaterC8IntervalOSg_tF + 200

Or

3  Repeat                         0x103854a18 $s6Repeat8RepeaterC8setPause33_97E5396AC7E12D74879B993A593805A9LL4from2toSbAC5StateO_AItF + 168
4  Repeat                         0x103854cfc $s6Repeat8RepeaterC9timeFired33_97E5396AC7E12D74879B993A593805A9LLyyF + 628
5  Repeat                         0x10385676c $s6Repeat8RepeaterC14configureTimer33_97E5396AC7E12D74879B993A593805A9LLSo24OS_dispatch_source_timer_pyFyycfU_TA + 60
6  Repeat                         0x103852b60 $sIeg_IeyB_TR + 28

`Resume` picks up from where the timer paused?

Great library, thanks for the hard work.

It appears that resuming a Repeat timer after it has been paused resets the interval.

For example: a 3-second interval timer is paused @ 2 seconds. Upon resuming it, it executes/fires instantly and then starts another 3-second cycle.

Expected behavior: after resuming, timer picks up the unfinished interval running for 1 second then firing (completing the interval that was paused before)

Added debouncer feature

Implement debounce features using Repeater class as core.
The debounce function is an extremely useful tool that can help throttle requests. It 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. If 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.

Example:

let debouncer = Debouncer(.seconds(10))
debouncer.callback = {
	// your code here
}

// Call debouncer to start the callback after the delayed time.
// Multiple calls will ignore the older calls and overwrite the firing time.
debouncer.call()

Not working on iOS 13.1

let rCheck = Repeater(interval: .seconds(5), mode: .infinite) { _ in
            
            print("OK")
        }

rCheck.start()

Not working

Added support for Throotler

Throttling 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.

Example:

let throttler = Throttler(time: .milliseconds(500), {
  // your code here
})

// Call throttler. Defined block will never be called more than once each specified interval.
throttler.call()

Fire 2 time in each repeat

I use the below code for print date and time every 2 second. but Repeat run inside code 2 time in each fire.
private var timer: Repeater?
self.timer = Repeater.every(.seconds(2)) { _ in
print("App from \(from) => \(String(self.gf.getCurrentDateTime()))")
}
Result in console is here:
App from vcChatMain => 20181130135222
App from vcChatMain => 20181130135222
App from vcChatMain => 20181130135224
App from vcChatMain => 20181130135224
App from vcChatMain => 20181130135226
App from vcChatMain => 20181130135226
App from vcChatMain => 20181130135228
App from vcChatMain => 20181130135228
As you see, every 2 second, print method fire 2 time. Why this problem occurred?

Getting crash on Throttler.swift line 100

Our application is live and we are getting too much crash on Throttler.swift line 100.

Below is the method where the application is crashing as per the fabric logs

	public func call() {
		callbackJob.cancel()
		callbackJob = DispatchWorkItem { [weak self] in
			if let selfStrong = self {
				selfStrong.lastExecutionTime = .now()
				selfStrong.waitingForPerform = false
			}
			self?.callback?()
		}

		let (now, dispatchTime) = self.evaluateDispatchTime()
		self.previousScheduled = now
		self.waitingForPerform = true

		queue.asyncAfter(deadline: dispatchTime, execute: callbackJob)
	}

Below is the line as per the fabric where the application is crashing
let (now, dispatchTime) = self.evaluateDispatchTime()

Below is the crash logs as per the fabric,

#12. Crashed: com.apple.root.default-qos
0 libobjc.A.dylib 0x20479c6ec objc_destructInstance + 36
1 libswiftCore.dylib 0x1066e75f0 swift_deallocClassInstance + 32
2 libswiftCore.dylib 0x1066e7584 swift_release_dealloc + 28
3 Repeat 0x106214004 Throttler.call() (Throttler.swift:100)
4 OneLinkHome 0x1046a5ed0 @objc AccessoryListViewController.checkIfSetupNeeded() ()
5 OneLinkHome 0x104559270 partial apply for closure #1 in background(
:) ()
6 OneLinkHome 0x104558a18 thunk for @escaping @callee_guaranteed () -> () ()
7 libdispatch.dylib 0x204ff56c8 _dispatch_call_block_and_release + 24
8 libdispatch.dylib 0x204ff6484 _dispatch_client_callout + 16
9 libdispatch.dylib 0x204fcca6c _dispatch_queue_override_invoke + 664
10 libdispatch.dylib 0x204fd8aec _dispatch_root_queue_drain + 344
11 libdispatch.dylib 0x204fd934c _dispatch_worker_thread2 + 116
12 libsystem_pthread.dylib 0x2051d917c _pthread_wqthread + 472
13 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

--

#0. com.apple.main-thread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 GraphicsServices 0x2077c0584 GSEventRunModal + 100
6 UIKitCore 0x23278ad40 UIApplicationMain + 212
7 OneLinkHome 0x1045291e4 main (AppDelegate.swift:20)
8 libdyld.dylib 0x205006bb4 start + 4

#1. com.apple.uikit.eventfetch-thread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 Foundation 0x205f3d494 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 300
6 Foundation 0x205f3d340 -[NSRunLoop(NSRunLoop) runUntilDate:] + 148
7 UIKitCore 0x23287b1f4 -[UIEventFetcher threadMain] + 136
8 Foundation 0x20607023c NSThread__start + 1040
9 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
10 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
11 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#2. GAIThread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 Foundation 0x205f3d494 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 300
6 Foundation 0x205f78e84 -[NSRunLoop(NSRunLoop) run] + 88
7 OneLinkHome 0x1048d1468 +[GAI threadMain:] + 4346827880
8 Foundation 0x20607023c NSThread__start + 1040
9 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
10 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
11 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#3. Thread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 Foundation 0x205f3d494 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 300
6 HomeKit 0x21da99fe8 -[_HMLocationHandler createLocationManager] + 496
7 Foundation 0x20607023c NSThread__start + 1040
8 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
9 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
10 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#4. com.apple.NSURLConnectionLoader
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 CFNetwork 0x205b6a00c -[__CoreSchedulingSetRunnable runForever] + 212
6 Foundation 0x20607023c NSThread__start + 1040
7 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
8 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
9 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#5. com.apple.CFSocket.private
0 libsystem_kernel.dylib 0x205153350 __select + 8
1 CoreFoundation 0x205555a38 __CFSocketManager + 620
2 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
3 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
4 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#6. com.twitter.crashlytics.ios.MachExceptionServer
0 OneLinkHome 0x104a2aac4 CLSProcessRecordAllThreads + 4348242628
1 OneLinkHome 0x104a2aac4 CLSProcessRecordAllThreads + 4348242628
2 OneLinkHome 0x104a2a980 CLSProcessRecordAllThreads + 4348242304
3 OneLinkHome 0x104a19e70 CLSHandler + 4348173936
4 OneLinkHome 0x104a14e84 CLSMachExceptionServer + 4348153476
5 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
6 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
7 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#7. JavaScriptCore bmalloc scavenger
0 libsystem_kernel.dylib 0x205152f0c __psynch_cvwait + 8
1 libsystem_pthread.dylib 0x2051d5410 _pthread_cond_wait$VARIANT$armv81 + 620
2 libc++.1.dylib 0x2047204d0 std::__1::condition_variable::wait(std::__1::unique_lockstd::__1::mutex&) + 24
3 JavaScriptCore 0x20c8fe9c8 void std::__1::condition_variable_any::wait<std::__1::unique_lockbmalloc::Mutex >(std::__1::unique_lockbmalloc::Mutex&) + 104
4 JavaScriptCore 0x20c902abc bmalloc::Scavenger::threadRunLoop() + 176
5 JavaScriptCore 0x20c9021f0 bmalloc::Scavenger::Scavenger(std::__1::lock_guardbmalloc::Mutex&) + 10
6 JavaScriptCore 0x20c903c9c std::__1::__thread_specific_ptrstd::__1::__thread_struct::set_pointer(std::__1::__thread_struct*) + 38
7 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
8 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
9 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#8. WebThread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 WebCore 0x20e3b6eec RunWebThread(void*) + 592
6 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
7 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
8 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#9. AVAudioSession Notify Thread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 AVFAudio 0x20b55a60c GenericRunLoopThread::Entry(void*) + 164
6 AVFAudio 0x20b586768 CAPThread::Entry(CAPThread*) + 88
7 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
8 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
9 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#10. Thread
0 libsystem_kernel.dylib 0x205153b9c __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x2051d9100 _pthread_wqthread + 348
2 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

#11. Thread
0 libsystem_kernel.dylib 0x205147ea4 mach_msg_trap + 8
1 libsystem_kernel.dylib 0x20514737c mach_msg + 72
2 CoreFoundation 0x20554cbe8 __CFRunLoopServiceMachPort + 236
3 CoreFoundation 0x205547a84 __CFRunLoopRun + 1396
4 CoreFoundation 0x2055471f0 CFRunLoopRunSpecific + 436
5 Foundation 0x205f3d494 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 300
6 AWSIoT 0x1054d2258 -[AWSIoTMQTTClient openStreams:] (AWSIoTMQTTClient.m:635)
7 Foundation 0x20607023c NSThread__start + 1040
8 libsystem_pthread.dylib 0x2051d825c _pthread_body + 128
9 libsystem_pthread.dylib 0x2051d81bc _pthread_start + 48
10 libsystem_pthread.dylib 0x2051dbcf4 thread_start + 4

#12. Crashed: com.apple.root.default-qos
0 libobjc.A.dylib 0x20479c6ec objc_destructInstance + 36
1 libswiftCore.dylib 0x1066e75f0 swift_deallocClassInstance + 32
2 libswiftCore.dylib 0x1066e7584 swift_release_dealloc + 28
3 Repeat 0x106214004 Throttler.call() (Throttler.swift:100)
4 OneLinkHome 0x1046a5ed0 @objc AccessoryListViewController.checkIfSetupNeeded() ()
5 OneLinkHome 0x104559270 partial apply for closure #1 in background(
:) ()
6 OneLinkHome 0x104558a18 thunk for @escaping @callee_guaranteed () -> () ()
7 libdispatch.dylib 0x204ff56c8 _dispatch_call_block_and_release + 24
8 libdispatch.dylib 0x204ff6484 _dispatch_client_callout + 16
9 libdispatch.dylib 0x204fcca6c _dispatch_queue_override_invoke + 664
10 libdispatch.dylib 0x204fd8aec _dispatch_root_queue_drain + 344
11 libdispatch.dylib 0x204fd934c _dispatch_worker_thread2 + 116
12 libsystem_pthread.dylib 0x2051d917c _pthread_wqthread + 472
13 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

#13. Thread
0 libsystem_kernel.dylib 0x205153b9c __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x2051d91c0 _pthread_wqthread + 540
2 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

#14. Thread
0 libsystem_pthread.dylib 0x2051dbce8 start_wqthread + 190

#15. Thread
0 libsystem_kernel.dylib 0x205153b9c __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x2051d91c0 _pthread_wqthread + 540
2 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

#16. Thread
0 libsystem_kernel.dylib 0x205153b9c __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x2051d91c0 _pthread_wqthread + 540
2 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

#17. Thread
0 libsystem_kernel.dylib 0x205153b9c __workq_kernreturn + 8
1 libsystem_pthread.dylib 0x2051d9100 _pthread_wqthread + 348
2 libsystem_pthread.dylib 0x2051dbcec start_wqthread + 4

immediateFire not work

for such testcase

    func test_throttleFirstImmediateFire() {
        let exp = expectation(description: "Run twice and call immediately")

        var value = 0
        let extractedExpr = Throttler(time: .milliseconds(500), immediateFire: true, {
            value += 1
        })
        self.throttle = extractedExpr

        self.throttle?.call()
        self.throttle?.call()
        self.throttle?.call()
        self.throttle?.call()
        self.throttle?.call()

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
            if value == 2 {
                exp.fulfill()
            } else {
                XCTAssert(value == 2, "Failed to throttle, calls were not ignored.")
            }
        }

        self.wait(for: [exp], timeout: 1)
    }

expect value == 2, first time and second time after 500ms.
but, this test case failed,
I guess
queue.asyncAfter(deadline: dispatchTime, execute: callbackJob) was cancel by second call()

Fail restarting paused timer

This error happens when you attempt to restart a paused timer; due to a bug it’s impossible and you are forced to use a new instance.

This error is already solved in 0.2.0 I’ll publish this Sunday.

Overflow Int in Repeater.Interval.Internal.second

On iPhone 5 with 32 bits processor it is possible to make int overflow. The underlay seconds:

/// Repeat interval
	public enum Interval {
              case seconds(_: Double)

		internal var value: DispatchTimeInterval {
			switch self {
			case .seconds(let value):			return .milliseconds(Int( Double(value) * Double(1000)))

which can exceeding the scope of int

Not working for me

Hello, perhaps I'm missing something.
I've created a new project and installed via CocoaPods.
Repeat is not firing:

    import UIKit
    import Repeat
    
    class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("view did load")
        // Do any additional setup after loading the view, typically from a nib.
        Repeater.once(after: .seconds(5)) { timer in
            print("tick")
        }
        let timer = Repeater(interval: .seconds(5), mode: .infinite) { _ in
            print("tock")
        }
        timer.start()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    }    

Thanks

Increased CPU Usage

First up, Great library. We've a light-weight macOS app that uses an infinite timer to update the UI. Since switching to Repeater, we've seen our app's CPU usage go by 5-10%. Is this something that can be avoided or are there any best practices to keep down the CPU usage/energy impact?

Thanks!

Timer's require strong references

No matter what function I use, every times requires a strong reference in order to fire.

Everything instantly deallocates itself if I dont have a strong reference. I'm creating multiple timers and dont want to have to declare a dozen variables to store all of these, thats just not practical.

Looking at the tests, I should be able to do this, however, the same thing appears to happen here.

let timer = Repeater(interval: .seconds(1), mode: .infinite) { timer in
    print("Timer")
}
timer.start()

Did I miss something in the readme about this requiring a strong reference of itself to continuously fire, or is this a bug? Been wracking my head out for about 2 hours trying to figure out what the hell was going on.

Thanks

Refactoring for timer state

Need to refactoring timer state removing variables like isRunning, adding three states (paused,running,finished) and allows the user to watch state change events.

This issue is already solved in 0.2.0 I’ll publish this Sunday.

fire() executes the closure in the current thread but not in the given dispatch queue

Description

Example code:

let timer = Repeater.every(.minutes(5), count: nil, tolerance: .seconds(1), queue: .global()) { 
 // Some long running operation... 
}
timer.fire()

Given the closure contains a relatively long-running operation, I use .global() queue for this purpose, but I want the closure to be run just after I schedule it because I need this operation to be run right now and not only after 5 mins.

Expected
The documentation doesn't tell me the aspects of force firing, so I think it is implied that the closure will be run in the queue that is given to the timer .

Actual
The closure is run in the current thread that may cause blocking of a blocking-sensible thread like the main.

Possible workaround
To fire the timer in a different queue.

DispatchQueue.global().async { timer.fire() }

Carthage static framework

When using Carthage [static frameworks], the linker fails. Simply unchecking Gather Coverage Data in Repeat's test scheme fixes this issue.

remainingIterations is now decreased before notifing observers

Hi, Great Code - Solved my unfiring timer when user drag content (imagine a quiz without a timeout LOL)

Well, in "timeFired()" maybe it's better to update the state of the timer and then notify the observers?
because the observers might use the timer state to update UI, and if I check "remainingIterations" I'll get 1 - but it's 0... and the last iteration that my code excepts will never happen =]

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.