Skip to content

Commit

Permalink
update demo and readme.
Browse files Browse the repository at this point in the history
1.2.0
  • Loading branch information
yulingtianxia committed May 10, 2018
1 parent 507bc00 commit f2ed33f
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 15 deletions.
16 changes: 12 additions & 4 deletions MTDemo/MTDemo/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand All @@ -21,18 +21,26 @@
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2ia-SP-fXG">
<rect key="frame" x="172" y="318" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Foo:"/>
<state key="normal" title="Fire!"/>
<connections>
<action selector="tapFoo:" destination="BYZ-38-t0r" eventType="touchUpInside" id="xal-N4-gAU"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Please Tap Foo:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pwc-Ao-gsU">
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Please Tap Fire:" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pwc-Ao-gsU">
<rect key="frame" x="0.0" y="487" width="375" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="4Jy-zc-NeT">
<rect key="frame" x="128" y="166" width="119" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Always Fire 1970!"/>
<connections>
<action selector="tapBar:" destination="BYZ-38-t0r" eventType="touchUpInside" id="akY-py-aWm"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
Expand Down
26 changes: 23 additions & 3 deletions MTDemo/MTDemo/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,27 @@ - (void)viewDidLoad {

// MTRule *rule = [[MTRule alloc] initWithTarget:self.stub selector:@selector(foo:) durationThreshold:1];
// rule.messageQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//
// rule.alwaysInvokeBlock = ^(MTRule *rule, NSDate *date) {
// if ([date isEqualToDate:[NSDate dateWithTimeIntervalSince1970:0]]) {
// return YES;
// }
// return NO;
// };
// [MTEngine.defaultEngine applyRule:rule];

// 跟上面的用法等价
[self.stub mt_limitSelector:@selector(foo:) oncePerDuration:0.5 usingMode:MTPerformModeDebounce onMessageQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
MTRule *rule = [self.stub mt_limitSelector:@selector(foo:) oncePerDuration:0.5 usingMode:MTPerformModeDebounce onMessageQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) alwaysInvokeBlock:^(MTRule *rule, NSDate *date) {
if ([date isEqualToDate:[NSDate dateWithTimeIntervalSince1970:0]]) {
return YES;
}
return NO;
}];
rule.alwaysInvokeBlock = ^(MTRule *rule, NSDate *date) {
if ([date isEqualToDate:[NSDate dateWithTimeIntervalSince1970:0]]) {
return YES;
}
return NO;
};
NSArray<MTRule *> *rules = self.stub.mt_allRules;
// self.stub = nil;

Expand All @@ -49,6 +65,10 @@ - (IBAction)tapFoo:(UIButton *)sender {
[self.stub foo:[NSDate date]];
}

- (IBAction)tapBar:(UIButton *)sender {
[self.stub foo:[NSDate dateWithTimeIntervalSince1970:0]];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
Expand All @@ -63,7 +83,7 @@ - (void)handleFooNotification:(NSNotification *)notification
df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:[NSTimeZone localTimeZone].secondsFromGMT];
NSString *localDateString = [df stringFromDate:date];
dispatch_async(dispatch_get_main_queue(), ^{
self.label.text = [NSString stringWithFormat:@"Last Tap Date: %@", localDateString];
self.label.text = [NSString stringWithFormat:@"Last Fire Date: %@", localDateString];
});
}

Expand Down
2 changes: 1 addition & 1 deletion MessageThrottle.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "MessageThrottle"
s.version = "1.1.3"
s.version = "1.2.0"
s.summary = "A lightweight Objective-C message throttle and debounce library."
s.description = <<-DESC
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.
Expand Down
19 changes: 16 additions & 3 deletions MessageThrottle/MessageThrottle.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ Class mt_metaClass(Class cls);
@property (nonatomic) MTPerformMode mode;

/**
是否过滤掉这条消息,block 的返回值为 BOOL 类型,参数列表与消息的方法列表相同。
如果返回 YES,则表明此条消息很重要,不能被忽略,无视节流限频。不会影响当前节流模式。
是否必须执行消息。block 的参数列表可选,返回值为 BOOL 类型。
block 传入的第一个参数为 `self`,其余参数列表与消息调用的参数列表相同。
block 如果返回 YES,则消息立即执行,但不会影响当前节流模式。
*/
@property (nonatomic) id messageFilterBlock;
@property (nonatomic) id alwaysInvokeBlock;

/**
MTModePerformLastly 和 MTModePerformDebounce 模式下消息发送的队列,默认在主队列
Expand Down Expand Up @@ -144,6 +145,18 @@ Class mt_metaClass(Class cls);
*/
- (nullable MTRule *)mt_limitSelector:(SEL)selector oncePerDuration:(NSTimeInterval)durationThreshold usingMode:(MTPerformMode)mode onMessageQueue:(dispatch_queue_t)messageQueue;

/**
对方法调用限频,可以指定方法某种情况下一定会调用
@param selector 限频的方法
@param durationThreshold 限频的阈值
@param mode 限频模式
@param messageQueue 延时执行方法的队列
@param alwaysInvokeBlock 是否必须执行消息。block 的参数列表可选,返回值为 BOOL 类型。参考 `MTRule`。
@return 如果限频成功则返回规则对象,否则返回 nil
*/
- (nullable MTRule *)mt_limitSelector:(SEL)selector oncePerDuration:(NSTimeInterval)durationThreshold usingMode:(MTPerformMode)mode onMessageQueue:(dispatch_queue_t)messageQueue alwaysInvokeBlock:(nullable id)alwaysInvokeBlock;

@end

NS_ASSUME_NONNULL_END
14 changes: 11 additions & 3 deletions MessageThrottle/MessageThrottle.m
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,11 @@ static SEL mt_aliasForSelector(Class cls, SEL selector)

static BOOL mt_invokeFilterBlock(MTRule *rule, NSInvocation *originalInvocation)
{
if (!rule.messageFilterBlock) {
if (!rule.alwaysInvokeBlock || ![rule.alwaysInvokeBlock isKindOfClass:NSClassFromString(@"NSBlock")]) {
NSLog(@"Not Block!");
return NO;
}
NSMethodSignature *filterBlockSignature = [NSMethodSignature signatureWithObjCTypes:mt_blockMethodSignature(rule.messageFilterBlock)];
NSMethodSignature *filterBlockSignature = [NSMethodSignature signatureWithObjCTypes:mt_blockMethodSignature(rule.alwaysInvokeBlock)];
NSInvocation *blockInvocation = [NSInvocation invocationWithMethodSignature:filterBlockSignature];
NSUInteger numberOfArguments = filterBlockSignature.numberOfArguments;

Expand Down Expand Up @@ -293,9 +294,10 @@ static BOOL mt_invokeFilterBlock(MTRule *rule, NSInvocation *originalInvocation)
[blockInvocation setArgument:argBuf atIndex:idx];
}

[blockInvocation invokeWithTarget:rule.messageFilterBlock];
[blockInvocation invokeWithTarget:rule.alwaysInvokeBlock];
BOOL returnedValue = NO;
[blockInvocation getReturnValue:&returnedValue];

if (argBuf != NULL) {
free(argBuf);
}
Expand Down Expand Up @@ -547,6 +549,11 @@ - (nullable MTRule *)mt_limitSelector:(SEL)selector oncePerDuration:(NSTimeInter
}

- (nullable MTRule *)mt_limitSelector:(SEL)selector oncePerDuration:(NSTimeInterval)durationThreshold usingMode:(MTPerformMode)mode onMessageQueue:(dispatch_queue_t)messageQueue
{
return [self mt_limitSelector:selector oncePerDuration:durationThreshold usingMode:mode onMessageQueue:messageQueue alwaysInvokeBlock:nil];
}

- (nullable MTRule *)mt_limitSelector:(SEL)selector oncePerDuration:(NSTimeInterval)durationThreshold usingMode:(MTPerformMode)mode onMessageQueue:(dispatch_queue_t)messageQueue alwaysInvokeBlock:(id)alwaysInvokeBlock
{
MTRule *rule = MTEngine.defaultEngine.rules[mt_methodDescription(self, selector)];
if (!rule) {
Expand All @@ -555,6 +562,7 @@ - (nullable MTRule *)mt_limitSelector:(SEL)selector oncePerDuration:(NSTimeInter
rule.durationThreshold = durationThreshold;
rule.mode = mode;
rule.messageQueue = messageQueue;
rule.alwaysInvokeBlock = alwaysInvokeBlock;
return [rule apply] ? rule : nil;
}

Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ MessageThrottle is a lightweight, simple library for controlling frequency of fo
- [x] Support 3 modes: Throttle(Firstly), Throttle(Last) and Debounce.
- [x] Centralized management of rules.
- [x] Self-managed rules.
- [x] Let method **MUST** invoke at the specified conditions.

## 🔮 Example

Expand All @@ -45,7 +46,7 @@ Stub *s = [Stub new];
MTRule *rule = [s limitSelector:@selector(foo:) oncePerDuration:0.01]; // returns MTRule instance
```

For more control of rule, you can use `mt_limitSelector:oncePerDuration:usingMode:onMessageQueue:`.
For more control of rule, you can use `mt_limitSelector:oncePerDuration:usingMode:onMessageQueue:alwaysInvokeBlock:`.

You can also start with a creation of `MTRule`:

Expand All @@ -55,9 +56,17 @@ Stub *s = [Stub new];
MTRule *rule = [[MTRule alloc] initWithTarget:s selector:@selector(foo:) durationThreshold:0.01];
rule.mode = MTModePerformLast; // Or `MTModePerformFirstly`, ect
rule.messageQueue = /** a dispatch queue you want, maybe `dispatch_get_main_queue()` whatever...*/
rule.alwaysInvokeBlock = ^(MTRule *rule, NSDate *date) {
if ([date isEqualToDate:[NSDate dateWithTimeIntervalSince1970:0]]) {
return YES;
}
return NO;
};
[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 `foo:` method.

```
Expand Down

0 comments on commit f2ed33f

Please sign in to comment.