MessageThrottle is a lightweight, simple library for controlling frequency of forwarding Objective-C messages. You can choose to control existing methods per instance or per class. It's an implementation of function throttle/debounce developed with Objective-C runtime. For a visual explaination of the differences between throttling and debouncing, see this demo.
- Objective-C Message Throttle and Debounce
- Associated Object and Dealloc
- MessageThrottle Performance Benchmark and Optimization
- MessageThrottle Safety
- Easy to use.
- Keep your code clear
- Reserve the whole arguments.
- Support instance, class and meta class.
- Support 3 modes: Throttle(Firstly), Throttle(Last) and Debounce.
- Centralized management of rules.
- Self-managed rules.
- Let method MUST invoke at the specified conditions.
- Persistent rules.
To run the example project, clone the repo and run MTDemo target.
🐒 How to use
The following example shows how to restrict the frequency of forwarding
- [ViewController foo:] message to 100 times per second.
Stub *s = [Stub new]; MTRule *rule = [s limitSelector:@selector(foo:) oncePerDuration:0.01]; // returns MTRule instance
For more control of rule, you can use
You can also start with a creation of
Stub *s = [Stub new]; // You can also assign `Stub.class` or `mt_metaClass(Stub.class)` to `target` argument. MTRule *rule = [[MTRule alloc] initWithTarget:s selector:@selector(foo:) durationThreshold:0.01]; rule.mode = MTModePerformLast; // Or `MTModePerformFirstly`, ect [rule apply];
You can let method MUST invoke at the specified conditions using
alwaysInvokeBlock. The example code above will invoke message immediately if its 1st parameter equals "1970". BTW,
alwaysInvokeBlock can has no parameter, or has one more
MTRule before message's parameter list.
You should call
discard method When you don't need limit
MTRule is self-managed. If the
target of rule is a object instance,
MTRule will discard itself automatically when the
target is deallocated.
Some rules may have large
durationThreshold. You can set property
YES, and save them on disk by calling
savePersistentRules method. These persistent rules will be applied after
MTEngine class is loaded.
savePersistentRules will be called automatically when receive terminate notification.
rule.persistent = YES; [MTEngine.defaultEngine savePersistentRules];
MTRule represents the rule of a message throttle, which contains strategy and frequency of sending messages.
You can assign an instance or (meta)class to
target property. When you assign an instance to
target, MessageThrottle will only restrict messages send to this instance. If you want to restrict a class method, just using
mt_metaClass() to get it's meta class, and assign the meta class to
target. Rules with instance
target won't conflict with each other, and have a higher priority than rules with class
NOTE: A message can only have one rule per class hierarchy. For example, If there is one rule of message
- [Stub foo:], you can't add another rule of message
- [SuperStub foo:] anymore. PS: Assume that
Stub is a subclass of
MTRule also define the mode of performing selector. There are three modes defined in
MTModePerformDebounce. This demo shows the difference between throttle and debounce.
The default mode is
MTModePerformDebounce will restart timer when another message arrives during
durationThreshold. So there must be a delay of
durationThreshold at least.
MTModePerformDebounce: start end | durationThreshold(old) | @----------------------@---------------------->> | | ignore will perform at end of new duration |--------------------------------------------->> | durationThreshold(new) | start end
MTModePerformFirstly will performs the first message and ignore all following messages during
MTModePerformFirstly: start end | durationThreshold | @-------------------------@----------@---------------@---------------->> | | | | perform immediately ignore ignore ignore
MTModePerformLast performs the last message at end time. Please note that does not perform message immediately, the delay could be
durationThreshold at most.
MTModePerformLast: start end | durationThreshold | @-------------------------@----------@---------------@---------------->> | | | | ignore ignore ignore will perform at end
MTModePerformDebounce, you can designate a dispatch queue which messages perform on. The
messageQueue is main queue by default.
MTModePerformDebounce modes will also use the last arguments to perform messages.
MTEngine is a singleton class. It manages all rules of message throttles. You can use
applyRule: method to apply a rule or update an old rule that already exists. Using it's
discardRule: method to discardRule a rule. There is also a readonly property
allRules for obtaining all rules in current application.
CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate MessageThrottle into your Xcode project using CocoaPods, specify it in your
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '11.0' use_frameworks! target 'MyApp' do pod 'MessageThrottle' end
You need replace "MyApp" with your project's name.
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 MessageThrottle into your Xcode project using Carthage, specify it in your
carthage update to build the framework and drag the built
MessageThrottleKit.framework into your Xcode project.
Just drag the "MessageThrottle" document folder into your project.
- If you need help or you'd like to ask a general question, open an issue.
- If you found a bug, open an issue.
- If you have a feature request, open an issue.
- If you want to contribute, submit a pull request.
MessageThrottle is available under the MIT license. See the LICENSE file for more info.