Skip to content

Commit 7846e79

Browse files
committed
fix
1 parent dc0fa89 commit 7846e79

8 files changed

Lines changed: 107 additions & 51 deletions

ZHIntersectionObserver.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
1616
#
1717

1818
spec.name = "ZHIntersectionObserver"
19-
spec.version = "0.0.2"
19+
spec.version = "0.0.3"
2020
spec.summary = "Intersection Observer for iOS."
2121

2222
# This description is used to generate tags and improve search results.

ZHIntersectionObserver/Example/Pages/ZHExample1ViewController.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,9 @@ - (void)viewDidLayoutSubviews {
190190
if (self.changingSize) {
191191
return;
192192
}
193+
if (UIApplication.sharedApplication.applicationState != UIApplicationStateActive) {
194+
return;
195+
}
193196
self.containerView.frame = self.view.bounds;
194197
self.targetView.frame = CGRectMake(0, 0, 250, 250);
195198
self.targetView.center = self.containerView.center;

ZHIntersectionObserver/Example/Pages/ZHExample2ViewController.m

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ @interface ZHExample2UITableViewCell : UITableViewCell
1414

1515
@implementation ZHExample2UITableViewCell
1616

17+
- (void)dealloc {
18+
NSLog(@"ZHExample2UITableViewCell dealloc");
19+
}
20+
1721
@end
1822

1923
@implementation ZHExample2ViewController
@@ -29,6 +33,12 @@ - (void)viewDidLoad {
2933

3034
self.view.backgroundColor = [UIColor whiteColor];
3135
self.tableView.rowHeight = 100;
36+
37+
/*
38+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
39+
[self.tableView reloadData];
40+
});
41+
*/
3242
}
3343

3444
- (void)updateNavigationItem {
@@ -65,11 +75,10 @@ - (void)handleChangeDelay {
6575

6676
- (void)initIntersectionObserver {
6777
IntersectionObserverContainerOptions *containerOptions = [IntersectionObserverContainerOptions initOptionsWithScope:@"Example2" rootMargin:UIEdgeInsetsMake(CGRectGetMaxY(self.navigationController.navigationBar.frame), 0, 0, 0) thresholds:@[@1] containerView:self.tableView intersectionDuration:self.isDelay ? 600 : 0 callback:^(NSString * _Nonnull scope, NSArray<IntersectionObserverEntry *> * _Nonnull entries) {
68-
NSLog(@"Example2: entries = %@", entries);
6978
for (NSInteger i = 0; i < entries.count; i++) {
7079
IntersectionObserverEntry *entry = entries[i];
7180
ZHExample2UITableViewCell *cell = (ZHExample2UITableViewCell *)entry.targetView;
72-
NSLog(@"zhoon entry, isInsecting = %@ index = %@", @(entry.isInsecting), entry.data[@"row"]);
81+
NSLog(@"Example2 entry, isInsecting = %@ index = %@", @(entry.isInsecting), entry.data[@"row"]);
7382
if (cell) {
7483
cell.backgroundColor = entry.isInsecting ? [[UIColor orangeColor] colorWithAlphaComponent:0.2] : [UIColor whiteColor];
7584
}

ZHIntersectionObserver/Source/IntersectionObserver.m

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#import "IntersectionObserver.h"
99
#import "IntersectionObserverOptions.h"
1010
#import "IntersectionObserverMeasure.h"
11+
#import "UIView+IntersectionObserver.h"
1112

1213
@implementation IntersectionObserver
1314

@@ -29,7 +30,7 @@ - (void)unobserve {
2930

3031
- (BOOL)addTargetOptions:(UIView *)target options:(IntersectionObserverTargetOptions *)options {
3132
if (target && options) {
32-
if ([self isTargetExisted:target]) {
33+
if ([self isTargetViewExisted:target]) {
3334
IntersectionObserverTargetOptions *oldOptions = [self.targetOptions objectForKey:target];
3435
BOOL isSameOptions = [IntersectionObserverMeasure isTargetOptions:options sameWithOptions:oldOptions];
3536
if (isSameOptions) {
@@ -39,6 +40,11 @@ - (BOOL)addTargetOptions:(UIView *)target options:(IntersectionObserverTargetOpt
3940
return YES;
4041
}
4142
} else {
43+
// view 不复用,但是 dataKey 一样,这个时候需要移除旧的 options
44+
UIView *existTarget = [self isTargetDataKeyExisted:options.dataKey];
45+
if (existTarget && target != existTarget) {
46+
[self.targetOptions removeObjectForKey:existTarget];
47+
}
4248
[self.targetOptions setObject:options forKey:target];
4349
return YES;
4450
}
@@ -50,7 +56,7 @@ - (BOOL)addTargetOptions:(UIView *)target options:(IntersectionObserverTargetOpt
5056

5157
- (BOOL)removeTargetOptions:(UIView *)target {
5258
if (target) {
53-
if ([self isTargetExisted:target]) {
59+
if ([self isTargetViewExisted:target]) {
5460
[self.targetOptions removeObjectForKey:target];
5561
return YES;
5662
} else {
@@ -62,7 +68,7 @@ - (BOOL)removeTargetOptions:(UIView *)target {
6268
}
6369
}
6470

65-
- (BOOL)isTargetExisted:(UIView *)target {
71+
- (BOOL)isTargetViewExisted:(UIView *)target {
6672
NSEnumerator<UIView *> *targets = self.targetOptions.keyEnumerator;
6773
BOOL exist = NO;
6874
for (UIView *aTarget in targets) {
@@ -74,6 +80,22 @@ - (BOOL)isTargetExisted:(UIView *)target {
7480
return exist;
7581
}
7682

83+
- (UIView *)isTargetDataKeyExisted:(NSString *)dataKey {
84+
if (!dataKey || dataKey.length <= 0) {
85+
return nil;
86+
}
87+
NSEnumerator<UIView *> *targets = self.targetOptions.keyEnumerator;
88+
UIView *view = nil;
89+
for (UIView *aTarget in targets) {
90+
IntersectionObserverTargetOptions *options = [self.targetOptions objectForKey:aTarget];
91+
if ([dataKey isEqualToString:options.dataKey]) {
92+
view = aTarget;
93+
break;
94+
}
95+
}
96+
return view;
97+
}
98+
7799
- (NSString *)description {
78100
return [NSString stringWithFormat:@"<%@, %p>: isObserving = %@, containerOptions = %@, targetOptions = %@", self.class, self, @(_isObserving), _containerOptions, _targetOptions];
79101
}

ZHIntersectionObserver/Source/IntersectionObserverManager.m

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ - (void)handleDidBecomeActiveNotification:(NSNotification *)notification {
5858
[self checkObserverWithScope:scope forTargetView:nil];
5959
}
6060
}
61-
self.previousApplicationState = UIApplicationStateActive;
61+
// 延迟设置
62+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
63+
if (UIApplication.sharedApplication.applicationState == UIApplicationStateActive) {
64+
self.previousApplicationState = UIApplicationStateActive;
65+
}
66+
});
6267
}
6368

6469
- (void)handleDidEnterBackgroundNotification:(NSNotification *)notification {
@@ -77,7 +82,12 @@ - (void)handleDidEnterBackgroundNotification:(NSNotification *)notification {
7782
[self checkObserverWithScope:scope forTargetView:nil];
7883
}
7984
}
80-
self.previousApplicationState = UIApplicationStateBackground;
85+
// 延迟设置
86+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
87+
if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {
88+
self.previousApplicationState = UIApplicationStateBackground;
89+
}
90+
});
8191
}
8292

8393
- (void)emitObserverEventWithScope:(NSString *)scope {

ZHIntersectionObserver/Source/IntersectionObserverMeasure.m

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ + (void)measureWithObserver:(IntersectionObserver *)observer forTargetView:(UIVi
125125
} else {
126126
[hideEntries addObject:entry];
127127
}
128-
if (!isInsecting || !delayReport) {
128+
if (!delayReportEntry) {
129129
options.previousInsecting = isInsecting;
130130
options.previousFixedInsecting = isInsecting;
131131
options.previousDataKey = options.dataKey;
@@ -156,28 +156,27 @@ + (void)measureWithObserver:(IntersectionObserver *)observer forTargetView:(UIVi
156156
}
157157

158158
if (reusedEntries.count > 0) {
159+
// 0.2s 之后检查被复用的 view 的 dataKey 是否还是曝光状态
159160
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
160-
if (reusedEntries.count > 0) {
161-
NSMutableArray *filterReusedEntries = [[NSMutableArray alloc] init];
162-
[reusedEntries enumerateObjectsUsingBlock:^(IntersectionObserverEntry * _Nonnull entry, NSUInteger idx, BOOL * _Nonnull stop) {
163-
BOOL removed = [[IntersectionObserverReuseManager shareInstance] isReusedDataKeyRemoved:entry.dataKey inScope:scope];
164-
if (!removed) {
165-
[filterReusedEntries addObject:entry];
166-
[[IntersectionObserverReuseManager shareInstance] removeReuseDataKey:entry.dataKey fromScope:scope];
167-
}
168-
}];
169-
[[IntersectionObserverReuseManager shareInstance] removeVisibleEntries:filterReusedEntries.copy fromScope:scope];
170-
if (containerOptions.callback && filterReusedEntries.count > 0) {
171-
containerOptions.callback(scope, filterReusedEntries);
161+
NSMutableArray *filterReusedEntries = [[NSMutableArray alloc] init];
162+
[reusedEntries enumerateObjectsUsingBlock:^(IntersectionObserverEntry * _Nonnull entry, NSUInteger idx, BOOL * _Nonnull stop) {
163+
BOOL removed = [[IntersectionObserverReuseManager shareInstance] isReusedDataKeyRemoved:entry.dataKey inScope:scope];
164+
if (!removed) {
165+
[filterReusedEntries addObject:entry];
166+
[[IntersectionObserverReuseManager shareInstance] removeReuseDataKey:entry.dataKey fromScope:scope];
172167
}
168+
}];
169+
[[IntersectionObserverReuseManager shareInstance] removeVisibleEntries:filterReusedEntries.copy fromScope:scope];
170+
if (containerOptions.callback && filterReusedEntries.count > 0) {
171+
containerOptions.callback(scope, filterReusedEntries);
173172
}
174173
});
175174
}
176175

177176
if (entries.count > 0) {
178177
if (delayReport) {
179178
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(containerOptions.intersectionDuration / 1000.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
180-
[self delayMeasureWithObserver:observer entries:entries.copy reusedEntries:reusedEntries.copy];
179+
[self delayMeasureWithObserver:observer entries:entries.copy];
181180
});
182181
} else {
183182
[[IntersectionObserverReuseManager shareInstance] addVisibleEntries:entries.copy toScope:scope];
@@ -193,8 +192,7 @@ + (void)measureWithObserver:(IntersectionObserver *)observer forTargetView:(UIVi
193192
}
194193

195194
+ (void)delayMeasureWithObserver:(IntersectionObserver *)observer
196-
entries:(NSArray <IntersectionObserverEntry *> *)entries
197-
reusedEntries:(NSArray <IntersectionObserverEntry *> *)reusedEntries {
195+
entries:(NSArray <IntersectionObserverEntry *> *)entries {
198196

199197
// 简单判断下当前 options 和 entries
200198
IntersectionObserverContainerOptions *containerOptions = observer.containerOptions;
@@ -233,7 +231,8 @@ + (void)delayMeasureWithObserver:(IntersectionObserver *)observer
233231
}
234232

235233
BOOL isInsecting = [self isInsectingWithRatio:ratio containerOptions:containerOptions targetOptions:options];
236-
BOOL canReport = [oldEntry.dataKey isEqualToString:options.dataKey] && isInsecting == oldEntry.isInsecting && ![[IntersectionObserverReuseManager shareInstance] isDataKeyVisible:options.dataKey inScope:scope];
234+
BOOL isDataKeyVisible = [[IntersectionObserverReuseManager shareInstance] isDataKeyVisible:options.dataKey inScope:scope];
235+
BOOL canReport = [oldEntry.dataKey isEqualToString:options.dataKey] && isInsecting == oldEntry.isInsecting && !isDataKeyVisible;
237236

238237
if (!canReport) {
239238
continue;
@@ -317,40 +316,41 @@ + (BOOL)canReportWithRatio:(CGFloat)ratio
317316

318317
BOOL isInsecting = [self isInsectingWithRatio:ratio containerOptions:containerOptions targetOptions:targetOptions];
319318

319+
BOOL isDataKeyVisible = targetOptions.dataKey ? [[IntersectionObserverReuseManager shareInstance] isDataKeyVisible:targetOptions.dataKey inScope:containerOptions.scope] : NO;
320+
320321
// 生命周期发生变化
321322
if (containerOptions.measureWhenAppStateChanged) {
322323
UIApplicationState prevApplicationState = [IntersectionObserverManager shareInstance].previousApplicationState;
323-
if (prevApplicationState != UIApplicationStateActive && UIApplication.sharedApplication.applicationState == UIApplicationStateActive) {
324-
return ![[IntersectionObserverReuseManager shareInstance] isDataKeyVisible:targetOptions.dataKey inScope:containerOptions.scope];
325-
// return isInsecting != targetOptions.previousInsecting;
324+
if (prevApplicationState != UIApplicationStateActive &&
325+
UIApplication.sharedApplication.applicationState == UIApplicationStateActive) {
326+
// TODO: 先直接返回 YES,这样导致那些那些一开始没曝光的 item 会发送多 isInsecting = NO 的通知
327+
// TODO: 如果改为 isInsecting != targetOptions.previousInsecting 会导致 cell 不复用的情况切换前后台无法触发事件
328+
return YES; // isInsecting != targetOptions.previousInsecting;
326329
}
327-
if (prevApplicationState != UIApplicationStateBackground && UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {
328-
return ![[IntersectionObserverReuseManager shareInstance] isDataKeyVisible:targetOptions.dataKey inScope:containerOptions.scope];
329-
// return isInsecting != targetOptions.previousInsecting;
330+
if (prevApplicationState != UIApplicationStateBackground &&
331+
UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) {
332+
// TODO: 先直接返回 YES,这样导致那些那些一开始没曝光的 item 会发送多 isInsecting = NO 的通知
333+
// TODO: 如果改为 isInsecting != targetOptions.previousInsecting 会导致 cell 不复用的情况切换前后台无法触发事件
334+
return YES; // isInsecting != targetOptions.previousInsecting;
330335
}
331336
}
332337

333-
// 可视状态发生变化
338+
// TODO: 可视状态发生变化
334339
/*
335340
if (containerOptions.measureWhenVisibilityChanged) {
336341
BOOL targetViewVisible = [self isTargetViewVisible:targetOptions.targetView inContainerView:containerOptions.containerView];
337342
BOOL containerViewVisible = [self isContainerViewVisible:containerOptions.containerView];
338343
if (targetViewVisible != targetOptions.previousVisible || containerViewVisible != containerOptions.previousVisible) {
339344
return isInsecting != targetOptions.previousInsecting;
340345
}
341-
}
342-
*/
346+
}*/
343347

344348
// 数据发生变化(或者复用)
345349
if (targetOptions.dataKey && targetOptions.dataKey.length > 0 && ![targetOptions.dataKey isEqualToString:targetOptions.previousDataKey]) {
346-
BOOL inVisiblePool = [[IntersectionObserverReuseManager shareInstance] isDataKeyVisible:targetOptions.dataKey inScope:containerOptions.scope];
347-
if ([targetOptions.dataKey isEqualToString:@"7"]) {
348-
NSLog(@"");
349-
}
350350
if (isInsecting) {
351-
return !inVisiblePool;
351+
return !isDataKeyVisible;
352352
} else {
353-
return inVisiblePool;
353+
return isDataKeyVisible;
354354
}
355355
}
356356

@@ -372,15 +372,15 @@ + (BOOL)isContainerViewVisible:(UIView *)containerView {
372372
}
373373

374374
+ (BOOL)isTargetViewVisible:(UIView *)targetView inContainerView:(UIView *)containerView {
375-
// 这里先不要做 hidden 这个判断了,有些场景例如 cell 复用,cell 会临时被 hidden 掉,所以先去掉这个逻辑
375+
// TODO: 这里先不要做 hidden 这个判断了,有些场景例如 cell 复用,cell 会临时被 hidden 掉,所以先去掉这个逻辑
376376
// BOOL flag = targetView.hidden || targetView.alpha <= 0 || !targetView.window;
377-
BOOL flag = targetView.alpha <= 0 || !targetView.window;
377+
BOOL flag = !targetView.window;
378378
if (flag) return NO;
379379
BOOL visible = YES;
380380
while (targetView.superview && targetView.superview != containerView) {
381381
targetView = targetView.superview;
382382
// flag = targetView.hidden || targetView.alpha <= 0 || !targetView.window;
383-
flag = targetView.alpha <= 0 || !targetView.window;
383+
flag = !targetView.window;
384384
if (flag) {
385385
visible = NO;
386386
break;

ZHIntersectionObserver/Source/IntersectionObserverReuseManager.m

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ - (instancetype)init {
2929

3030
- (BOOL)isDataKeyVisible:(NSString *)dataKey inScope:(NSString *)scope {
3131
if (!dataKey || dataKey.length <= 0) {
32-
NSLog(@"Warning: IntersectionObserverReuseManager no dataKey,当前如果不是复用的 view 可以不用管");
32+
// NSLog(@"Warning: IntersectionObserverReuseManager no dataKey,当前如果不是复用的 view 可以不用管");
3333
return NO;
3434
}
3535
if (!scope || scope.length <= 0) {
@@ -42,7 +42,7 @@ - (BOOL)isDataKeyVisible:(NSString *)dataKey inScope:(NSString *)scope {
4242

4343
- (void)addVisibleDataKey:(NSString *)dataKey toScope:(NSString *)scope {
4444
if (!dataKey || dataKey.length <= 0) {
45-
NSLog(@"Warning: IntersectionObserverReuseManager no dataKey,当前如果不是复用的 view 可以不用管");
45+
// NSLog(@"Warning: IntersectionObserverReuseManager no dataKey,当前如果不是复用的 view 可以不用管");
4646
return;
4747
}
4848
if (!scope || scope.length <= 0) {
@@ -66,7 +66,7 @@ - (void)addVisibleEntries:(NSArray <IntersectionObserverEntry *> *)entries toSco
6666

6767
- (void)removeVisibleDataKey:(NSString *)dataKey fromScope:(NSString *)scope {
6868
if (!dataKey || dataKey.length <= 0) {
69-
NSLog(@"Warning: IntersectionObserverReuseManager no dataKey,当前如果不是复用的 view 可以不用管");
69+
// NSLog(@"Warning: IntersectionObserverReuseManager no dataKey,当前如果不是复用的 view 可以不用管");
7070
return;
7171
}
7272
if (!scope || scope.length <= 0) {
@@ -131,14 +131,14 @@ - (void)removeReuseDataKey:(NSString *)dataKey fromScope:(NSString *)scope {
131131
- (BOOL)isReusedDataKeyRemoved:(NSString *)dataKey inScope:(NSString *)scope {
132132
if (!dataKey || dataKey.length <= 0) {
133133
NSLog(@"Warning: IntersectionObserverReuseManager no dataKey");
134-
return NO;
134+
return YES;
135135
}
136136
if (!scope || scope.length <= 0) {
137137
NSAssert(NO, @"");
138-
return NO;
138+
return YES;
139139
}
140140
if (!self.reusedDataKeys || self.reusedDataKeys.count <= 0) {
141-
return NO;
141+
return YES;
142142
}
143143
NSString *key = [NSString stringWithFormat:@"%@_%@", scope, dataKey];
144144
BOOL removed = ![self.reusedDataKeys containsObject:key];

ZHIntersectionObserver/Source/UIView+IntersectionObserver.m

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,16 +247,28 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
247247
[_view handleViewVisibilityChangedEventForTargetView:_view.intersectionObserverTargetOptions ? _view : nil];
248248
}
249249
}
250+
/*
250251
if ([keyPath isEqualToString:@"alpha"] && _view.intersectionObserverContainerOptions.measureWhenVisibilityChanged) {
251252
if ([change[NSKeyValueChangeOldKey] doubleValue] != [change[NSKeyValueChangeNewKey] doubleValue]) {
252-
[_view handleViewVisibilityChangedEventForTargetView:_view.intersectionObserverTargetOptions ? _view : nil];
253+
// 延迟设置
254+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
255+
if (self->_view.alpha == [change[NSKeyValueChangeNewKey] doubleValue]) {
256+
[self->_view handleViewVisibilityChangedEventForTargetView:self->_view.intersectionObserverTargetOptions ? self->_view : nil];
257+
}
258+
});
253259
}
254260
}
255261
if ([keyPath isEqualToString:@"hidden"] && _view.intersectionObserverContainerOptions.measureWhenVisibilityChanged) {
256262
if ([change[NSKeyValueChangeOldKey] boolValue] != [change[NSKeyValueChangeNewKey] boolValue]) {
257-
[_view handleViewVisibilityChangedEventForTargetView:_view.intersectionObserverTargetOptions ? _view : nil];
263+
// 延迟设置
264+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
265+
if (self->_view.hidden == [change[NSKeyValueChangeNewKey] boolValue]) {
266+
[self->_view handleViewVisibilityChangedEventForTargetView:self->_view.intersectionObserverTargetOptions ? self->_view : nil];
267+
}
268+
});
258269
}
259270
}
271+
*/
260272
}
261273
}
262274

0 commit comments

Comments
 (0)