Elegant ⏱ interface for Swift apps

Overview

Each

Elegant interface for Swift apps

BuddyBuild

Each is a NSTimer bridge library written in Swift.

Features

  • Completely configurable timers
  • Support for time intervals in ms, seconds, minutes and hours
  • Fully extendable
  • More readable and simple to use in comparison with NSTimer object

Requirements

  • iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+
  • Xcode 8.0+
  • Swift 3.0+

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

CocoaPods 1.1.0+ is required to build Each.

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

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target '<Your Target Name>' do
pod 'Each', '~> 1.2'
end

Then, run the following command:

$ pod install

Carthage

You can use Carthage to install Each by adding it to your Cartfile:

github "dalu93/Each"

Usage

Creating a new timer instance

let timer = Each(1).seconds     // Can be .milliseconds, .seconds, .minute, .hours  

Performing operations

timer.perform {
    // Do your operations
    // This closure has to return a NextStep value
    // Return .continue if you want to leave the timer active, otherwise
    // return .stop to invalidate it
}

If you want to leave the memory management decision to the Each class, you can simply use the perform(on: _) method. It requires that the parameter is an AnyObject instance.

timer.perform(on: self) {
    // Do your operations
    // This closure has to return a NextStep value
    // Return .continue if you want to leave the timer active, otherwise
    // return .stop to invalidate it
}

Stopping the timer manually

timer.stop()    // This stops immediately the timer

Restarting the timer

You can restart the timer only after you stopped it. This method restarts the timer with the same perform closure.

timer.restart()

Leaks

Unfortunately the interface doesn't help you with handling the memory leaks the timer could create. In case of them, two workarounds are provided

Workaround 1

Use the perform(on: _) method as explained in the usage section. Please note that using this method, the timer isn't immediately deallocated when the owner is deallocated. It will be deallocated when the timer triggers the next time and it will check whether the owner instance is still valid or not.

Workaround 2

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 3

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

License

Each is released under the MIT license. See LICENSE for details.

Comments
  • pod install error

    pod install error

    My 'Podfile':

    source 'https://github.com/CocoaPods/Specs.git'
    platform :ios, '8.0'
    target 'XXX' do
      use_frameworks!
      pod 'Each', '~> 1.2'
    end
    

    And, pod install the error is

    [!] Unable to satisfy the following requirements:
    
    - `Each (~> 1.2)` required by `Podfile`
    
    None of your spec sources contain a spec satisfying the dependency: `Each (~> 1.2)`.
    
    You have either:
     * out-of-date source repos which you can update with `pod repo update`.
     * mistyped the name or version.
     * not added the source repo that hosts the Podspec to your Podfile.
    
    Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
    

    but, if I delete pod 'Each', '~> 1.2' the other pods is available

    bug 
    opened by HexCD 2
  • Make the `perform` closure return type more readable

    Make the `perform` closure return type more readable

    Actually the return type is Bool

    timer.perform {
        // return `true` if you want to stop the timer, otherwise `false` to continue
    }
    

    In an implemented way where we want to stop the timer after doing something(), the code below isn't readable by other developers

    timer.perform {
        self.something()
        return true    // what does true mean? To continue it or to stop it?
    }
    

    A better way could be to declare an enum NextStep (as mentioned by @DeveloperPans) which encapsulates better the return type's meaning

    enum NextStep {
    
        case stop
        case `continue`
    }
    

    Which has a fileprivate extension that converts the enum to a Bool for the perform closure. The final result for the user will be

    timer.perform {
        self.something()
        return .stop/.continue
    }
    
    enhancement 
    opened by dalu93 2
  • Adding perform(on: _) method

    Adding perform(on: _) method

    This method provides an automatic memory leak detection.

    By simply using

    final class BVC: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            Each(1).seconds.perform(on: self) {
                print("timer called")
                return .continue
            }
        }
    
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(animated)
    
            self.dismiss(animated: true, completion: nil)
        }
    }
    

    The timer will be released whenever the owner will be released. Actually, the timer is released when it clocks and checks for the owner instance (if it's nil): the timer can be still allocated when the owner is released, but it will be released as soon as possible when it clocks the next time

    opened by dalu93 1
  • Fix #4

    Fix #4

    • Fixed #4
    • Use NextStep enum replace Bool make users understand the meaning easily
    • ChangeisStopped property access control to private(set)
    • More Swifty APIs
    opened by MrPans 1
  • Add `Disposable` concept

    Add `Disposable` concept

    To workaround the memory leak issue, an another idea could be to implement the famous pattern of Disposable and Disposer

    // MARK: - Disposable declaration
    public protocol Disposable {
        func dispose()
    }
    
    // MARK: - Disposable
    extension Each: Disposable {
        public func dispose() {
            stop()
        }
    }
    
    // MARK: - Disposer declaration
    public protocol Disposer {
        func add(_ disposable: Disposable)
        func dispose()
    }
    
    enhancement memory-leak 
    opened by dalu93 0
Owner
Luca D'Alberti
Swift Developer @ MSD
Luca D'Alberti
A complete set of primitives for concurrency and reactive programming on Swift

A complete set of primitives for concurrency and reactive programming on Swift 1.4.0 is the latest and greatest, but only for Swift 4.2 and 5.0 use 1.

AsyncNinja 156 Aug 31, 2022
Futures is a cross-platform framework for simplifying asynchronous programming, written in Swift.

Futures Futures is a cross-platform framework for simplifying asynchronous programming, written in Swift. It's lightweight, fast, and easy to understa

David Ask 60 Aug 11, 2022
GroupWork is an easy to use Swift framework that helps you orchestrate your concurrent, asynchronous functions in a clean and organized way

GroupWork is an easy to use Swift framework that helps you orchestrate your concurrent, asynchronous functions in a clean and organized way. This help

Quan Vo 42 Oct 5, 2022
Hydra ⚡️ Lightweight full-featured Promises, Async & Await Library in Swift

Lightweight full-featured Promises, Async & Await Library in Swift What's this? Hydra is full-featured lightweight library which allows you to write b

Daniele Margutti 2k Dec 24, 2022
Kommander is a Swift library to manage the task execution in different threads.

A lightweight, pure-Swift library for manage the task execution in different threads. Through the definition a simple but powerful concept, Kommand.

Intelygenz 173 Apr 11, 2022
SwiftCoroutine - Swift coroutines for iOS, macOS and Linux.

Many languages, such as Kotlin, Go, JavaScript, Python, Rust, C#, C++ and others, already have coroutines support that makes the async/await pattern i

Alex Belozierov 808 Dec 1, 2022
Venice - Coroutines, structured concurrency and CSP for Swift on macOS and Linux.

Venice provides structured concurrency and CSP for Swift. Features Coroutines Coroutine cancelation Coroutine groups Channels Receive-only chan

Zewo 1.5k Dec 22, 2022
Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch

Async Now more than syntactic sugar for asynchronous dispatches in Grand Central Dispatch (GCD) in Swift Async sugar looks like this: Async.userInitia

Tobias Due Munk 4.6k Dec 27, 2022
AwaitKit is a powerful Swift library which provides a powerful way to write asynchronous code in a sequential manner.

AwaitKit is a powerful Swift library inspired by the Async/Await specification in ES8 (ECMAScript 2017) which provides a powerful way to write asynchronous code in a sequential manner.

Yannick Loriot 752 Dec 5, 2022
GCDTimer - Well tested Grand Central Dispatch (GCD) Timer in Swift

GCDTimer Well tested Grand Central Dispatch (GCD) Timer in Swift. Checkout the test file. Usage Long running timer import GCDTimer

Hemant Sapkota 183 Sep 9, 2022
Schedule timing task in Swift using a fluent API. (A friendly alternative to Timer)

Schedule(简体中文) Schedule is a timing tasks scheduler written in Swift. It allows you run timing tasks with elegant and intuitive syntax. Features Elega

Luo Xiu 1.8k Jan 7, 2023
Grand Central Dispatch simplified with swift.

GCDKit GCDKit is Grand Central Dispatch simplified with Swift. for Swift 1.2: Use version 1.0.1 for Swift 2.1 / 2.2: Use the master branch Introductio

John Estropia 317 Dec 6, 2022
Queues, timers, and task groups in Swift

Dispatcher eases the pain of using Grand Central Dispatch by introducing 4 new Swift classes. Dispatcher Queue Group Timer Requirements Swift 2.0+ Ins

Alec Larson 109 Jan 29, 2022
A wrapper of Grand Central Dispatch written in Swift

GCD A wrapper of Grand Central Dispatch written in Swift. Examples gcd // submit your code for asynchronous execution on a global queue with high prio

Le Van Nghia 75 May 19, 2022
A Swift microframework for very easy atomic values.

Atomic Atomic is a fast, safe class for making values thread-safe in Swift. It is backed by pthread_mutex_lock which is the fastest, most-efficient lo

Adlai Holler 36 Sep 26, 2022
Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch (iOS7+ and OS X 10.9+ compatible)

Async.legacy Syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch (GCD) Async rewritten for iOS7 and OS X 10.9 Compatibility

Joseph Lord 31 Jul 1, 2019
⏳ Collection of Swift 5.5 async/await utility functions.

⏳ FunAsync Collection of Swift 5.5 async/await utility functions. Throw <-> Result conversion asyncThrowsToAsyncResult asyncResultToAsyncThrows More C

Yasuhiro Inami 23 Oct 14, 2022
🎭 Swift async/await & Actor-powered effectful state-management framework.

?? Actomaton ??‍?? Actor + ?? Automaton = ?? Actomaton Actomaton is Swift async/await & Actor-powered effectful state-management framework inspired by

Yasuhiro Inami 199 Dec 20, 2022
AutoLogout is a swift library for managing user's session on inactivity.

On user inactivity, it will show an alert box to continue session or Logout as shown in screen shot, according to time set.

Adnan Yousaf 9 Jul 7, 2022