Skip to content

Commit 1f66748

Browse files
author
王洋洋
committed
Release 4.5.5
1 parent ae6c3cf commit 1f66748

File tree

9 files changed

+257
-74
lines changed

9 files changed

+257
-74
lines changed

SensorsAnalyticsSDK.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "SensorsAnalyticsSDK"
3-
s.version = "4.5.4"
3+
s.version = "4.5.5"
44
s.summary = "The official iOS SDK of Sensors Analytics."
55
s.homepage = "http://www.sensorsdata.cn"
66
s.source = { :git => 'https://github.com/sensorsdata/sa-sdk-ios.git', :tag => "v#{s.version}" }

SensorsAnalyticsSDK.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,8 @@
465465
F226E68428BC646F000443A7 /* UIView+SAElementPath.h in Headers */ = {isa = PBXBuildFile; fileRef = F226E68228BC646F000443A7 /* UIView+SAElementPath.h */; };
466466
F226E68528BC646F000443A7 /* UIView+SAElementPath.m in Sources */ = {isa = PBXBuildFile; fileRef = F226E68328BC646F000443A7 /* UIView+SAElementPath.m */; };
467467
F226E68C28BC993C000443A7 /* SAUIViewElementProperties.h in Headers */ = {isa = PBXBuildFile; fileRef = F226E68A28BC993C000443A7 /* SAUIViewElementProperties.h */; };
468+
F22B8BB729A7177B0022975C /* NSObject+SAKeyValueObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = F22B8BB529A7177B0022975C /* NSObject+SAKeyValueObserver.h */; };
469+
F22B8BB829A7177B0022975C /* NSObject+SAKeyValueObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = F22B8BB629A7177B0022975C /* NSObject+SAKeyValueObserver.m */; };
468470
F22E1B1B26A55C8A0033A748 /* SAAppPageLeaveTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = F22E1B1926A55C8A0033A748 /* SAAppPageLeaveTracker.h */; };
469471
F22E1B1C26A55C8A0033A748 /* SAAppPageLeaveTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = F22E1B1A26A55C8A0033A748 /* SAAppPageLeaveTracker.m */; };
470472
F23CA0052701715E002EEACA /* WKWebView+SABridge.h in Headers */ = {isa = PBXBuildFile; fileRef = F23C9FFE2701715E002EEACA /* WKWebView+SABridge.h */; };
@@ -1042,6 +1044,8 @@
10421044
F226E68228BC646F000443A7 /* UIView+SAElementPath.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+SAElementPath.h"; sourceTree = "<group>"; };
10431045
F226E68328BC646F000443A7 /* UIView+SAElementPath.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+SAElementPath.m"; sourceTree = "<group>"; };
10441046
F226E68A28BC993C000443A7 /* SAUIViewElementProperties.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAUIViewElementProperties.h; sourceTree = "<group>"; };
1047+
F22B8BB529A7177B0022975C /* NSObject+SAKeyValueObserver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+SAKeyValueObserver.h"; sourceTree = "<group>"; };
1048+
F22B8BB629A7177B0022975C /* NSObject+SAKeyValueObserver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SAKeyValueObserver.m"; sourceTree = "<group>"; };
10451049
F22E1B1926A55C8A0033A748 /* SAAppPageLeaveTracker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAAppPageLeaveTracker.h; sourceTree = "<group>"; };
10461050
F22E1B1A26A55C8A0033A748 /* SAAppPageLeaveTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAAppPageLeaveTracker.m; sourceTree = "<group>"; };
10471051
F23C9FFE2701715E002EEACA /* WKWebView+SABridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WKWebView+SABridge.h"; sourceTree = "<group>"; };
@@ -1611,6 +1615,8 @@
16111615
F21C226628F7B0E500847823 /* NSDictionary+SACopyProperties.m */,
16121616
F296FF022935A3DF00C40C48 /* NSObject+SAToString.h */,
16131617
F296FF032935A3DF00C40C48 /* NSObject+SAToString.m */,
1618+
F22B8BB529A7177B0022975C /* NSObject+SAKeyValueObserver.h */,
1619+
F22B8BB629A7177B0022975C /* NSObject+SAKeyValueObserver.m */,
16141620
);
16151621
path = Utils;
16161622
sourceTree = "<group>";
@@ -2501,6 +2507,7 @@
25012507
F2FBBBAE28A39D2200F75293 /* UIView+ExposureListener.h in Headers */,
25022508
FC0A8C63276334F200109267 /* SADeepLinkConstants.h in Headers */,
25032509
F20231D028C33ECD0034D8B3 /* UIScrollView+SADelegateHashTable.h in Headers */,
2510+
F22B8BB729A7177B0022975C /* NSObject+SAKeyValueObserver.h in Headers */,
25042511
4D5F3AC22833B280003A2C0A /* SADatabaseInterceptor.h in Headers */,
25052512
4D41D9D325FF7E9300D856F4 /* UIViewController+SAElementPath.h in Headers */,
25062513
F273487528A9E92C00C34E64 /* UIScrollView+ExposureListener.h in Headers */,
@@ -2857,6 +2864,7 @@
28572864
F2E9723225E637820009A2B9 /* SAAppPushManager.m in Sources */,
28582865
FCBECDFC27DEDF7200361D6C /* SARequestDeepLinkProcessor.m in Sources */,
28592866
881A41FC253D7B5000854F69 /* SASwizzle.m in Sources */,
2867+
F22B8BB829A7177B0022975C /* NSObject+SAKeyValueObserver.m in Sources */,
28602868
F28997D8273B6D66005E7D5E /* SAGesturePlugin.m in Sources */,
28612869
881A4207253D7B5000854F69 /* SAHTTPSession.m in Sources */,
28622870
88B58FC92732394E00B83DCC /* SAItemEventObject.m in Sources */,

SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
#import "SALimitKeyManager.h"
6565
#import "NSDictionary+SACopyProperties.h"
6666

67-
#define VERSION @"4.5.4"
67+
#define VERSION @"4.5.5"
6868

6969
void *SensorsAnalyticsQueueTag = &SensorsAnalyticsQueueTag;
7070

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// NSObject+SAKeyValueObserver.h
3+
// SensorsAnalyticsSDK
4+
//
5+
// Created by 陈玉国 on 2023/2/23.
6+
// Copyright © 2015-2023 Sensors Data Co., Ltd. All rights reserved.
7+
//
8+
// Licensed under the Apache License, Version 2.0 (the "License");
9+
// you may not use this file except in compliance with the License.
10+
// You may obtain a copy of the License at
11+
//
12+
// http://www.apache.org/licenses/LICENSE-2.0
13+
//
14+
// Unless required by applicable law or agreed to in writing, software
15+
// distributed under the License is distributed on an "AS IS" BASIS,
16+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
// See the License for the specific language governing permissions and
18+
// limitations under the License.
19+
//
20+
21+
#import <Foundation/Foundation.h>
22+
23+
NS_ASSUME_NONNULL_BEGIN
24+
25+
@interface SAKVOObject : NSObject
26+
27+
@property (nonatomic, copy) NSString *keyPath;
28+
@property (nonatomic, copy) NSValue *context;
29+
30+
- (instancetype)initWithKeyPath:(NSString *)keyPath context:(void *)context;
31+
32+
@end
33+
34+
@interface NSObject (SAKeyValueObserver)
35+
//As a target, added observer infos
36+
@property (nonatomic, strong) NSMutableDictionary <NSString *, NSArray <SAKVOObject *> *>*sensorsdata_KVO_observerInfos;
37+
//As a observer, target infos
38+
@property (nonatomic, strong) NSMutableDictionary *sensorsdata_KVO_targetInfos;
39+
40+
- (void)sensorsdata_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
41+
42+
//avoid crash for KVO
43+
- (void)sensorsdata_dealloc;
44+
45+
/// observer mark
46+
@property (nonatomic, strong, nullable) NSHashTable *sensorsdata_KVO_observers;
47+
48+
/// target mark
49+
@property (nonatomic, strong, nullable) NSHashTable *sensorsdata_KVO_targets;
50+
51+
@end
52+
53+
NS_ASSUME_NONNULL_END
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//
2+
// NSObject+SAKeyValueObserver.m
3+
// SensorsAnalyticsSDK
4+
//
5+
// Created by 陈玉国 on 2023/2/23.
6+
// Copyright © 2015-2023 Sensors Data Co., Ltd. All rights reserved.
7+
//
8+
// Licensed under the Apache License, Version 2.0 (the "License");
9+
// you may not use this file except in compliance with the License.
10+
// You may obtain a copy of the License at
11+
//
12+
// http://www.apache.org/licenses/LICENSE-2.0
13+
//
14+
// Unless required by applicable law or agreed to in writing, software
15+
// distributed under the License is distributed on an "AS IS" BASIS,
16+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
// See the License for the specific language governing permissions and
18+
// limitations under the License.
19+
//
20+
21+
#if ! __has_feature(objc_arc)
22+
#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file.
23+
#endif
24+
25+
#import "NSObject+SAKeyValueObserver.h"
26+
#import <objc/runtime.h>
27+
#import "SALog.h"
28+
29+
static void *const kSAKVOObserverInfosKey = (void *)&kSAKVOObserverInfosKey;
30+
static void *const kSAKVOTargetInfosKey = (void *)&kSAKVOTargetInfosKey;
31+
static void *const kSAKVOObserversKey = (void *)&kSAKVOObserversKey;
32+
static void *const kSAKVOTargetsKey = (void *)&kSAKVOTargetsKey;
33+
34+
@implementation SAKVOObject
35+
36+
- (instancetype)initWithKeyPath:(NSString *)keyPath context:(void *)context {
37+
if (self = [super init]) {
38+
_keyPath = keyPath;
39+
_context = [NSValue valueWithPointer:context];
40+
}
41+
return self;
42+
}
43+
44+
@end
45+
46+
@implementation NSObject (SAKeyValueObserver)
47+
48+
- (void)setSensorsdata_KVO_observerInfos:(NSMutableDictionary *)sensorsdata_KVO_observerInfos {
49+
objc_setAssociatedObject(self, kSAKVOObserverInfosKey, sensorsdata_KVO_observerInfos, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
50+
}
51+
52+
- (NSMutableDictionary *)sensorsdata_KVO_observerInfos {
53+
NSMutableDictionary *observerInfos = objc_getAssociatedObject(self, kSAKVOObserverInfosKey);
54+
if (!observerInfos) {
55+
observerInfos = [NSMutableDictionary dictionary];
56+
self.sensorsdata_KVO_observerInfos = observerInfos;
57+
}
58+
return observerInfos;
59+
}
60+
61+
- (void)setSensorsdata_KVO_targetInfos:(NSMutableDictionary *)sensorsdata_KVO_targetInfos {
62+
objc_setAssociatedObject(self, kSAKVOTargetInfosKey, sensorsdata_KVO_targetInfos, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
63+
}
64+
65+
- (NSMutableDictionary *)sensorsdata_KVO_targetInfos {
66+
NSMutableDictionary *targetInfos = objc_getAssociatedObject(self, kSAKVOTargetInfosKey);
67+
if (!targetInfos) {
68+
targetInfos = [NSMutableDictionary dictionary];
69+
self.sensorsdata_KVO_targetInfos = targetInfos;
70+
}
71+
return targetInfos;
72+
}
73+
74+
- (void)setSensorsdata_KVO_observers:(NSHashTable * _Nullable)sensorsdata_KVO_observers {
75+
objc_setAssociatedObject(self, kSAKVOObserversKey, sensorsdata_KVO_observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
76+
}
77+
78+
- (NSHashTable *)sensorsdata_KVO_observers {
79+
return objc_getAssociatedObject(self, kSAKVOObserversKey);
80+
}
81+
82+
- (void)setSensorsdata_KVO_targets:(NSHashTable * _Nullable)sensorsdata_KVO_targets {
83+
objc_setAssociatedObject(self, kSAKVOTargetsKey, sensorsdata_KVO_targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
84+
}
85+
86+
- (NSHashTable *)sensorsdata_KVO_targets {
87+
return objc_getAssociatedObject(self, kSAKVOTargetsKey);
88+
}
89+
90+
- (void)sensorsdata_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
91+
if (![self shouldAddObserver:observer forKeyPath:keyPath context:context]) {
92+
return;
93+
}
94+
[self addObserver:observer forKeyPath:keyPath options:options context:context];
95+
}
96+
97+
- (BOOL)shouldAddObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context {
98+
if (!observer || !keyPath) {
99+
return NO;
100+
}
101+
NSString *observerAddress = [NSString stringWithFormat:@"%p", observer];
102+
NSArray <SAKVOObject *>*observerInfos = self.sensorsdata_KVO_observerInfos[observerAddress];
103+
if (!observerInfos) {
104+
observerInfos = [NSArray array];
105+
}
106+
//filter observer infos to check if existed same observer info
107+
NSArray *existedObserverInfos = [observerInfos filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
108+
SAKVOObject *tempObserverInfo = evaluatedObject;
109+
NSString *tempKeyPath = tempObserverInfo.keyPath;
110+
NSValue *tempContext = tempObserverInfo.context;
111+
return [tempKeyPath isEqualToString:keyPath] && [tempContext isEqualToValue:[NSValue valueWithPointer:context]];
112+
}]];
113+
if (existedObserverInfos.count > 0) {
114+
return NO;
115+
}
116+
//add observer and target info
117+
SAKVOObject *observerInfo = [[SAKVOObject alloc] initWithKeyPath:keyPath context:context];
118+
NSMutableArray <SAKVOObject *>*tempObserverInfos = [NSMutableArray arrayWithArray:observerInfos];
119+
[tempObserverInfos addObject:observerInfo];
120+
self.sensorsdata_KVO_observerInfos[observerAddress] = [tempObserverInfos copy];
121+
NSString *targetAddress = [NSString stringWithFormat:@"%p", self];
122+
NSArray <SAKVOObject *>*targetInfos = observer.sensorsdata_KVO_targetInfos[targetAddress];
123+
NSMutableArray <SAKVOObject *>*tempTargetInfos = [NSMutableArray array];
124+
if (targetInfos) {
125+
[tempTargetInfos addObjectsFromArray:targetInfos];
126+
}
127+
[tempTargetInfos addObject:observerInfo];
128+
observer.sensorsdata_KVO_targetInfos[targetAddress] = [tempTargetInfos copy];
129+
if (!self.sensorsdata_KVO_observers) {
130+
self.sensorsdata_KVO_observers = [NSHashTable weakObjectsHashTable];
131+
}
132+
if (!observer.sensorsdata_KVO_targets) {
133+
observer.sensorsdata_KVO_targets = [NSHashTable weakObjectsHashTable];
134+
}
135+
[self.sensorsdata_KVO_observers addObject:observer];
136+
[observer.sensorsdata_KVO_targets addObject:self];
137+
138+
return YES;
139+
}
140+
141+
- (void)removeKVOWhenDealloc {
142+
@try {
143+
[self removeKVOTargetsWhenDealloc];
144+
[self removeKVOObserversWhenDealloc];
145+
} @catch (NSException *exception) {
146+
SALogError(@"remove KVO exception: %@", exception);
147+
} @finally {
148+
}
149+
}
150+
151+
- (void)removeKVOTargetsWhenDealloc {
152+
if (!self.sensorsdata_KVO_targets) {
153+
return;
154+
}
155+
for (NSObject *target in self.sensorsdata_KVO_targets) {
156+
NSString *targetAddress = [NSString stringWithFormat:@"%p", target];
157+
for (SAKVOObject *targetInfo in self.sensorsdata_KVO_targetInfos[targetAddress]) {
158+
[target removeObserver:self forKeyPath:targetInfo.keyPath context:targetInfo.context.pointerValue];
159+
}
160+
}
161+
}
162+
163+
- (void)removeKVOObserversWhenDealloc {
164+
if (!self.sensorsdata_KVO_observers) {
165+
return;
166+
}
167+
for (NSObject *observer in self.sensorsdata_KVO_observers) {
168+
NSString *observerAddress = [NSString stringWithFormat:@"%p", observer];
169+
for (SAKVOObject *observerInfo in self.sensorsdata_KVO_observerInfos[observerAddress]) {
170+
[self removeObserver:observer forKeyPath:observerInfo.keyPath context:observerInfo.context.pointerValue];
171+
}
172+
}
173+
}
174+
175+
- (void)sensorsdata_dealloc {
176+
//remove observer info
177+
[self removeKVOWhenDealloc];
178+
[self sensorsdata_dealloc];
179+
}
180+
181+
@end

SensorsAnalyticsSDK/Exposure/SAExposureManager.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#import "UIViewController+ExposureListener.h"
3434
#import "SAMethodHelper.h"
3535
#import "SALog.h"
36+
#import "NSObject+SAKeyValueObserver.h"
3637

3738

3839
static NSString *const kSAExposureViewMark = @"sensorsdata_exposure_mark";
@@ -150,6 +151,7 @@ - (void)swizzleMethods {
150151
[UICollectionView sa_swizzleMethod:@selector(setDelegate:) withMethod:@selector(sensorsdata_exposure_setDelegate:) error:NULL];
151152
[UIViewController sa_swizzleMethod:@selector(viewDidAppear:) withMethod:@selector(sensorsdata_exposure_viewDidAppear:) error:NULL];
152153
[UIViewController sa_swizzleMethod:@selector(viewDidDisappear:) withMethod:@selector(sensorsdata_exposure_viewDidDisappear:) error:NULL];
154+
[NSObject sa_swizzleMethod:NSSelectorFromString(@"dealloc") withMethod:@selector(sensorsdata_dealloc) error:NULL];
153155
}
154156

155157
- (void)applicationDidEnterBackground {

0 commit comments

Comments
 (0)