From a231653ad82ac23dfd2545361b578d6321b83de9 Mon Sep 17 00:00:00 2001 From: YoloMao Date: Wed, 11 Oct 2023 09:45:38 +0800 Subject: [PATCH] fix: swizzle bug (#279) * fix: swizzle bug * ci: update ci * chore: update podfile lock * style: code format --------- Co-authored-by: GIOSDK --- .../SwizzleTests/GrowingSwizzleTest.m | 520 ++++++++++++------ Example/Podfile.lock | 136 ++--- GrowingAnalytics.podspec | 4 +- .../UICollectionView+GrowingAutotracker.m | 35 +- .../UITableView+GrowingAutotracker.m | 33 +- Package.swift | 2 +- 6 files changed, 466 insertions(+), 264 deletions(-) diff --git a/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m b/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m index d649eae77..d0f9e7acf 100644 --- a/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m +++ b/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m @@ -24,20 +24,17 @@ #import "GrowingULSwizzle.h" #import "GrowingULSwizzler.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#pragma clang diagnostic ignored "-Wincomplete-implementation" + static NSInteger b = 0; @interface Growing_Swizzle_XCTest : NSObject - (void)instanceMethod; -- (void)instanceMethod:(NSString *)arg1; - -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2; - -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3; - -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3 arg4:(NSString *)arg4; - + (void)classMethod; @end @@ -45,27 +42,69 @@ + (void)classMethod; @implementation Growing_Swizzle_XCTest - (void)instanceMethod { - b = 1; } + (void)classMethod { - b = 2; } -- (void)instanceMethod:(NSString *)arg1 { - b = 3; -} +@end + +@interface Growing_Swizzle_XCTest_B : Growing_Swizzle_XCTest + +@end + +@implementation Growing_Swizzle_XCTest_B + +@end + +@interface Growing_Swizzle_XCTest_C : Growing_Swizzle_XCTest_B + +@end + +@implementation Growing_Swizzle_XCTest_C + +@end + +@interface Growing_Swizzle_XCTest_D : Growing_Swizzle_XCTest_B -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 { - b = 4; +@end + +@implementation Growing_Swizzle_XCTest_D + +- (void)instanceMethod { + [super instanceMethod]; } -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3 { - b = 5; +@end + +@interface Growing_Swizzle_XCTest_B_2 : Growing_Swizzle_XCTest + +@end + +@implementation Growing_Swizzle_XCTest_B_2 + +@end + +@interface Growing_Swizzle_XCTest_D_2 : Growing_Swizzle_XCTest_B_2 + +@end + +@implementation Growing_Swizzle_XCTest_D_2 + +- (void)instanceMethod { + [super instanceMethod]; } -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3 arg4:(NSString *)arg4 { - b = 6; +@end + +@interface Growing_Swizzle_XCTest_E : Growing_Swizzle_XCTest_B + +@end + +@implementation Growing_Swizzle_XCTest_E + +- (void)instanceMethod { + } @end @@ -81,11 +120,11 @@ + (void)swizzle_classMethod; @implementation Growing_Swizzle_XCTest (XCTest) - (void)swizzle_instanceMethod { - b = 6; + b++; } + (void)swizzle_classMethod { - b = 7; + b += 2; } @end @@ -100,9 +139,6 @@ - (void)delegateSelector2; @end -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincomplete-implementation" - @implementation Growing_Swizzle_Proxy_XCTest - (instancetype)initWithTarget:(id)target { @@ -125,8 +161,6 @@ + (BOOL)resolveInstanceMethod:(SEL)sel { @end -#pragma clang diagnostic pop - @interface Growing_Swizzle_Proxy_XCTest2 : NSProxy @property (nonatomic, weak) id target; @@ -137,9 +171,6 @@ - (void)delegateSelector; @end -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincomplete-implementation" - @implementation Growing_Swizzle_Proxy_XCTest2 - (instancetype)initWithTarget:(id)target { @@ -153,187 +184,351 @@ - (id)forwardingTargetForSelector:(SEL)aSelector { @end -#pragma clang diagnostic pop - @interface GrowingULSwizzleTest : XCTestCase +@property (nonatomic, strong) NSMutableString *swizzleString; + @end @implementation GrowingULSwizzleTest - (void)setUp { // Put setup code here. This method is called before the invocation of each test method in the class. + self.swizzleString = @"".mutableCopy; } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. } -- (void)test0GrowingULSwizzler { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 8; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod]; - XCTAssertEqual(b, 8); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod]; - XCTAssertEqual(b, 1); - } +- (void)generalSwizzleClass:(Class)cls selector:(SEL)sel { + __weak typeof(self) weakSelf = self; + __block NSInvocation *invocation = nil; + invocation = [cls growingul_swizzleMethod:sel withBlock:^(id obj) { + [invocation invokeWithTarget:obj]; + [weakSelf.swizzleString appendString:@"A"]; + } error:nil]; +} - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 9; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod:@""]; - XCTAssertEqual(b, 9); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod:) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod:@""]; - XCTAssertEqual(b, 3); - } +- (void)guSwizzleClass:(Class)cls selector:(SEL)sel key:(const void *)key mode:(GrowingULSwizzleMode)mode { + __weak typeof(self) weakSelf = self; + GrowingULSwizzleInstanceMethod(cls, + sel, + GUSWReturnType(void), + GUSWArguments(), + GUSWReplacement({ + GUSWCallOriginal(); + [weakSelf.swizzleString appendString:@"B"]; + }), mode, key); +} +- (void)test01InstanceSwizzlingInModeOncePerClassAndSuperclasses { + SEL selector = @selector(instanceMethod); + static const void *key = &key; + + // hook子类B + [self guSwizzleClass:Growing_Swizzle_XCTest_B.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + + // 父类没有调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @""); + + // 子类正常调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_B new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 子类如果没有重写,则调用用的是父类的,会调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_C new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 子类如果重写且调用super,则触发1次 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_D new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // hook子类D + [self guSwizzleClass:Growing_Swizzle_XCTest_D.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + + // 子类如果重写且调用super,先后hook了B和B的子类D,则触发1次;此为ModeOncePerClassAndSuperclasses的作用 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_D new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 异常情况1:如果先hook子类(重写且调用super),再hook父类的话,则会触发2次 { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:arg2:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 10; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod:@"" arg2:@""]; - XCTAssertEqual(b, 10); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod:arg2:) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod:@"" arg2:@""]; - XCTAssertEqual(b, 4); + [self guSwizzleClass:Growing_Swizzle_XCTest_D_2.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + [self guSwizzleClass:Growing_Swizzle_XCTest_B_2.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + // B_2正常调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_B_2 new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // D_2会触发2次;此为异常情况 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_D_2 new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BB"); } - + + // 异常情况2:子类如果重写且没调用super,则swizzle不生效 { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:arg2:arg3:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 11; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod:@"" arg2:@"" arg3:@""]; - XCTAssertEqual(b, 11); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod:arg2:arg3:) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod:@"" arg2:@"" arg3:@""]; - XCTAssertEqual(b, 5); + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_E new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @""); } +} - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b *= 2; - } - named:@"xctest"]; - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b *= 3; - } - named:@"xctest2"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod]; - XCTAssertEqual(b, 6); - - ((void (*)(id, SEL, SEL, Class))objc_msgSend)(GrowingULSwizzler.class, - @selector(growing_unswizzleSelector:onClass:), - @selector(instanceMethod), - Growing_Swizzle_XCTest.class); - [test instanceMethod]; - XCTAssertEqual(b, 1); +- (void)test02ClassSwizzling { + Class cls = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(classMethod); + __block NSMutableString *swizzleString = self.swizzleString; + + // hook子类B + GrowingULSwizzleClassMethod(cls, + selector, + GUSWReturnType(void), + GUSWArguments(), + GUSWReplacement({ + GUSWCallOriginal(); + [swizzleString appendString:@"B"]; + })); + + // 父类没有调用swizzle方法 + self.swizzleString.string = @""; + [Growing_Swizzle_XCTest classMethod]; + XCTAssertEqualObjects(self.swizzleString, @""); + + // 子类正常调用swizzle方法 + self.swizzleString.string = @""; + [Growing_Swizzle_XCTest_B classMethod]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 子类如果没有重写,则调用用的是父类的,会调用swizzle方法 + self.swizzleString.string = @""; + [Growing_Swizzle_XCTest_C classMethod]; + XCTAssertEqualObjects(self.swizzleString, @"B"); +} + +- (void)test03AlwaysSwizzlingMode { + // GrowingULSwizzleModeAlways的swizzle一直触发 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls selector:selector key:NULL mode:GrowingULSwizzleModeAlways]; + [self guSwizzleClass:cls2 selector:selector key:NULL mode:GrowingULSwizzleModeAlways]; } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BBBBBB"); +} - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(respondsToSelector:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 12; - } - named:@"xctest"]; +- (void)test04SwizzleOncePerClassMode { + // GrowingULSwizzleModeOncePerClass只能保证分别对父类和子类只swizzle一次 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + static const void *key = &key; + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClass]; + [self guSwizzleClass:cls2 selector:selector key:key mode:GrowingULSwizzleModeOncePerClass]; } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BB"); +} - { - XCTAssertThrows([GrowingULSwizzler growingul_swizzleSelector:@selector(cannotFindMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - } - named:@"xctest"]); - - XCTAssertThrows([GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:arg2:arg3:arg4:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - } - named:@"xctest"]); +- (void)test05SwizzleOncePerClassOrSuperClassesMode { + // 先swizzle父类,再swizzle子类,GrowingULSwizzleModeOncePerClassAndSuperclasses保证只swizzle一次 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + static const void *key = &key; + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + [self guSwizzleClass:cls2 selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); +} - XCTAssertNoThrow([GrowingULSwizzler growing_printSwizzles]); -#pragma clang diagnostic pop +- (void)test06SwizzleOncePerClassOrSuperClassesMode2 { + // 先swizzle子类,再swizzle父类,GrowingULSwizzleModeOncePerClassAndSuperclasses就只能保证分别对父类和子类只swizzle一次 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + static const void *key = &key; + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls2 selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BB"); } -- (void)test0GrowingULSwizzlerRealDelegate { +- (void)test07GrowingULSwizzlerRealDelegate { // NSProxy id proxy = nil; id proxy1 = [[Growing_Swizzle_Proxy_XCTest alloc] initWithTarget:nil]; id proxy2 = [[Growing_Swizzle_Proxy_XCTest2 alloc] initWithTarget:proxy1]; { - XCTAssertNoThrow([GrowingULSwizzler realDelegate:proxy toSelector:@selector(delegateSelector)]); + XCTAssertNoThrow([GrowingULSwizzle realDelegate:proxy toSelector:@selector(delegateSelector)]); // proxy 本身实现了 - id result = [GrowingULSwizzler realDelegate:proxy1 toSelector:@selector(delegateSelector)]; + id result = [GrowingULSwizzle realDelegate:proxy1 toSelector:@selector(delegateSelector)]; XCTAssertEqualObjects(proxy1, result); - XCTAssertTrue([GrowingULSwizzler realDelegateClass:((NSObject *)result).class + XCTAssertTrue([GrowingULSwizzle realDelegateClass:((NSObject *)result).class respondsToSelector:@selector(delegateSelector)]); // proxy 在 resolveInstanceMethod 增加了实现 - id result2 = [GrowingULSwizzler realDelegate:proxy1 toSelector:@selector(delegateSelector2)]; + id result2 = [GrowingULSwizzle realDelegate:proxy1 toSelector:@selector(delegateSelector2)]; XCTAssertEqualObjects(proxy1, result2); - XCTAssertTrue([GrowingULSwizzler realDelegateClass:((NSObject *)result2).class + XCTAssertTrue([GrowingULSwizzle realDelegateClass:((NSObject *)result2).class respondsToSelector:@selector(delegateSelector2)]); } { // proxy 在 forwardingTargetForSelector 转发给了另一个对象 - id result = [GrowingULSwizzler realDelegate:proxy2 toSelector:@selector(delegateSelector)]; + id result = [GrowingULSwizzle realDelegate:proxy2 toSelector:@selector(delegateSelector)]; XCTAssertEqualObjects(proxy1, result); - XCTAssertTrue([GrowingULSwizzler realDelegateClass:((NSObject *)result).class + XCTAssertTrue([GrowingULSwizzle realDelegateClass:((NSObject *)result).class respondsToSelector:@selector(delegateSelector)]); } } -- (void)test1GrowingULSwizzle { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" +- (void)test08SwizzleCompatibility { + // 先执行generalSwizzle + Class cls = Growing_Swizzle_XCTest.class; + SEL selector = @selector(instanceMethod); + + __weak typeof(self) weakSelf = self; + void(^checkBlock)(NSString *) = ^(NSString *string) { + weakSelf.swizzleString.string = @""; + [[cls new] performSelector:selector]; + XCTAssertEqualObjects(weakSelf.swizzleString, string); + }; + + // generalSwizzleImp -> originImp + // A + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"A"); + + // rsSwizzleImp -> generalSwizzleImp -> originImp + // B <- A + static const void *key = &key; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"AB"); + + // generalSwizzleImp -> rsSwizzleImp -> generalSwizzleImp -> originImp + // A <- B <- A + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"ABA"); + + // generalSwizzleImp -> rsSwizzleImp -> generalSwizzleImp -> originImp + // A <- B <- A + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"ABA"); + + // generalSwizzleImp -> generalSwizzleImp -> rsSwizzleImp -> generalSwizzleImp -> originImp + // A <- A <- B <- A + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"ABAA"); +} + +- (void)test09SwizzleCompatibility { + // 先执行rsSwizzle + Class cls = Growing_Swizzle_XCTest.class; + SEL selector = @selector(instanceMethod); + + __weak typeof(self) weakSelf = self; + void(^checkBlock)(NSString *) = ^(NSString *string) { + weakSelf.swizzleString.string = @""; + [[cls new] performSelector:selector]; + XCTAssertEqualObjects(weakSelf.swizzleString, string); + }; + + // rsSwizzleImp -> originImp + // B + static const void *key = &key; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"B"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BA"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"BA"); + + // generalSwizzleImp -> generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BAA"); +} + +- (void)test10SwizzleCompatibility { + // isaSwizzler + Class cls = Growing_Swizzle_XCTest.class; + SEL selector = @selector(instanceMethod); + + Growing_Swizzle_XCTest *instance = [cls new]; + __weak typeof(self) weakSelf = self; + void(^checkBlock)(NSString *) = ^(NSString *string) { + weakSelf.swizzleString.string = @""; + [instance performSelector:selector]; + XCTAssertEqualObjects(weakSelf.swizzleString, string); + }; + + NSString *newClassName = [NSString stringWithFormat:@"%@_%@", [NSUUID UUID].UUIDString, + NSStringFromClass(cls)]; + Class generatedClass = objc_allocateClassPair(cls, newClassName.UTF8String, 0); + objc_registerClassPair(generatedClass); + object_setClass(instance, generatedClass); + + // isaSwizzler最后还是需要在动态子类中重写并调用父类方法,因此只要保证对父类的swizzler正常生效即可 + + // rsSwizzleImp -> originImp + // B + static const void *key = &key; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"B"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BA"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"BA"); + + // generalSwizzleImp -> generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BAA"); +} + +- (void)test11GrowingULSwizzle { NSError *error = nil; [Growing_Swizzle_XCTest growingul_swizzleMethod:@selector(undefinedSelector) withMethod:@selector(swizzle_instanceMethod) @@ -353,7 +548,7 @@ - (void)test1GrowingULSwizzle { XCTAssertNil(error); Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; [test instanceMethod]; - XCTAssertEqual(b, 6); + XCTAssertEqual(b, 1); error = nil; [Growing_Swizzle_XCTest growingul_swizzleClassMethod:@selector(classMethod) @@ -361,8 +556,9 @@ - (void)test1GrowingULSwizzle { error:&error]; XCTAssertNil(error); [Growing_Swizzle_XCTest classMethod]; - XCTAssertEqual(b, 7); -#pragma clang diagnostic pop + XCTAssertEqual(b, 3); } @end + +#pragma clang diagnostic pop diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 4723499b7..ef37df1e4 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,64 +1,64 @@ PODS: - - GrowingAnalytics/Advert (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/APM (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) + - GrowingAnalytics/Advert (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/APM (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) - GrowingAPM/Core - - GrowingAnalytics/Autotracker (4.0.0): - - GrowingAnalytics/AutotrackerCore (= 4.0.0) - - GrowingAnalytics/DefaultServices (= 4.0.0) - - GrowingAnalytics/Hybrid (= 4.0.0) - - GrowingAnalytics/MobileDebugger (= 4.0.0) - - GrowingAnalytics/WebCircle (= 4.0.0) - - GrowingAnalytics/AutotrackerCore (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingUtils/AutotrackerCore (= 0.0.7) - - GrowingAnalytics/Compression (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/Database (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/DefaultServices (4.0.0): - - GrowingAnalytics/Compression (= 4.0.0) - - GrowingAnalytics/Encryption (= 4.0.0) - - GrowingAnalytics/JSON (= 4.0.0) - - GrowingAnalytics/Network (= 4.0.0) - - GrowingAnalytics/Protobuf (= 4.0.0) - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/Encryption (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/Hybrid (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/ImpressionTrack (4.0.0): - - GrowingAnalytics/AutotrackerCore (= 4.0.0) - - GrowingAnalytics/JSON (4.0.0): - - GrowingAnalytics/Database (= 4.0.0) - - GrowingAnalytics/MobileDebugger (4.0.0): - - GrowingAnalytics/Screenshot (= 4.0.0) - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/WebSocket (= 4.0.0) - - GrowingAnalytics/Network (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/Protobuf (4.0.0): - - GrowingAnalytics/Database (= 4.0.0) - - GrowingAnalytics/Protobuf/Proto (= 4.0.0) - - GrowingAnalytics/Protobuf/Proto (4.0.0): - - GrowingAnalytics/Database (= 4.0.0) + - GrowingAnalytics/Autotracker (4.0.0-beta): + - GrowingAnalytics/AutotrackerCore (= 4.0.0-beta) + - GrowingAnalytics/DefaultServices (= 4.0.0-beta) + - GrowingAnalytics/Hybrid (= 4.0.0-beta) + - GrowingAnalytics/MobileDebugger (= 4.0.0-beta) + - GrowingAnalytics/WebCircle (= 4.0.0-beta) + - GrowingAnalytics/AutotrackerCore (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingUtils/AutotrackerCore (= 1.0.0) + - GrowingAnalytics/Compression (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/Database (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/DefaultServices (4.0.0-beta): + - GrowingAnalytics/Compression (= 4.0.0-beta) + - GrowingAnalytics/Encryption (= 4.0.0-beta) + - GrowingAnalytics/JSON (= 4.0.0-beta) + - GrowingAnalytics/Network (= 4.0.0-beta) + - GrowingAnalytics/Protobuf (= 4.0.0-beta) + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/Encryption (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/Hybrid (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/ImpressionTrack (4.0.0-beta): + - GrowingAnalytics/AutotrackerCore (= 4.0.0-beta) + - GrowingAnalytics/JSON (4.0.0-beta): + - GrowingAnalytics/Database (= 4.0.0-beta) + - GrowingAnalytics/MobileDebugger (4.0.0-beta): + - GrowingAnalytics/Screenshot (= 4.0.0-beta) + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/WebSocket (= 4.0.0-beta) + - GrowingAnalytics/Network (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/Protobuf (4.0.0-beta): + - GrowingAnalytics/Database (= 4.0.0-beta) + - GrowingAnalytics/Protobuf/Proto (= 4.0.0-beta) + - GrowingAnalytics/Protobuf/Proto (4.0.0-beta): + - GrowingAnalytics/Database (= 4.0.0-beta) - Protobuf (>= 3.22.0) - - GrowingAnalytics/Screenshot (4.0.0): + - GrowingAnalytics/Screenshot (4.0.0-beta): - GrowingAnalytics/TrackerCore - - GrowingAnalytics/Tracker (4.0.0): - - GrowingAnalytics/DefaultServices (= 4.0.0) - - GrowingAnalytics/MobileDebugger (= 4.0.0) - - GrowingAnalytics/TrackerCore (= 4.0.0) - - GrowingAnalytics/TrackerCore (4.0.0): - - GrowingUtils/TrackerCore (= 0.0.7) - - GrowingAnalytics/WebCircle (4.0.0): - - GrowingAnalytics/AutotrackerCore (= 4.0.0) - - GrowingAnalytics/Hybrid (= 4.0.0) - - GrowingAnalytics/Screenshot (= 4.0.0) - - GrowingAnalytics/WebSocket (= 4.0.0) - - GrowingAnalytics/WebSocket (4.0.0): - - GrowingAnalytics/TrackerCore (= 4.0.0) + - GrowingAnalytics/Tracker (4.0.0-beta): + - GrowingAnalytics/DefaultServices (= 4.0.0-beta) + - GrowingAnalytics/MobileDebugger (= 4.0.0-beta) + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) + - GrowingAnalytics/TrackerCore (4.0.0-beta): + - GrowingUtils/TrackerCore (= 1.0.0) + - GrowingAnalytics/WebCircle (4.0.0-beta): + - GrowingAnalytics/AutotrackerCore (= 4.0.0-beta) + - GrowingAnalytics/Hybrid (= 4.0.0-beta) + - GrowingAnalytics/Screenshot (= 4.0.0-beta) + - GrowingAnalytics/WebSocket (= 4.0.0-beta) + - GrowingAnalytics/WebSocket (4.0.0-beta): + - GrowingAnalytics/TrackerCore (= 4.0.0-beta) - GrowingAPM (0.0.15): - GrowingAPM/Core (= 0.0.15) - GrowingAPM/CrashMonitor (= 0.0.15) @@ -103,9 +103,9 @@ PODS: - GrowingToolsKit/Core - GrowingToolsKit/XPathTrack (1.2.1): - GrowingToolsKit/Core - - GrowingUtils/AutotrackerCore (0.0.7): + - GrowingUtils/AutotrackerCore (1.0.0): - GrowingUtils/TrackerCore - - GrowingUtils/TrackerCore (0.0.7) + - GrowingUtils/TrackerCore (1.0.0) - KIF (3.8.9): - KIF/Core (= 3.8.9) - KIF/Core (3.8.9) @@ -114,12 +114,12 @@ PODS: - LBXScan/Types (2.3) - LBXScan/UI (2.3): - LBXScan/Types (~> 2.2) - - Protobuf (3.24.3) + - Protobuf (3.24.4) - SDCycleScrollView (1.82): - SDWebImage (>= 5.0.0) - - SDWebImage (5.18.1): - - SDWebImage/Core (= 5.18.1) - - SDWebImage/Core (5.18.1) + - SDWebImage (5.18.2): + - SDWebImage/Core (= 5.18.2) + - SDWebImage/Core (5.18.2) DEPENDENCIES: - GrowingAnalytics/Advert (from `../`) @@ -150,16 +150,16 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - GrowingAnalytics: ea695e9b0ceeefbf6b4cebaeaa88f6867713a0d1 + GrowingAnalytics: 7f5da039bce1b155fb10e2d5699049a4b984fb1a GrowingAPM: 83118328af06eec2a987f47b8e62a9d6d986994c GrowingToolsKit: 134a78b023c4ab7da51e0a1111e9956a96e42dab - GrowingUtils: e8ba72794651ade9ad60a71662d11baa08d526c8 + GrowingUtils: f0a9858cfd15dc584367957f24a784813a68d637 KIF: 7660c626b0f2d4562533590960db70a36d640558 LBXScan: e51449f0832d1fe17da632af0d22adeb3cfa3543 - Protobuf: 970f7ee93a3a08e3cf64859b8efd95ee32b4f87f + Protobuf: 351e9022fe13a6e2af00e9aefc22077cb88520f8 SDCycleScrollView: a0d74c3384caa72bdfc81470bdbc8c14b3e1fbcf - SDWebImage: ebdbcebc7933a45226d9313bd0118bc052ad458b + SDWebImage: c0de394d7cf7f9838aed1fd6bb6037654a4572e4 PODFILE CHECKSUM: eadc8a2cddef5401cfafd1d713a6bacab48232e6 -COCOAPODS: 1.12.1 +COCOAPODS: 1.13.0 diff --git a/GrowingAnalytics.podspec b/GrowingAnalytics.podspec index 85caccc92..601d64ebe 100644 --- a/GrowingAnalytics.podspec +++ b/GrowingAnalytics.podspec @@ -40,7 +40,7 @@ GrowingAnalytics具备自动采集基本的用户行为事件,比如访问和 end s.subspec 'TrackerCore' do |trackerCore| - trackerCore.dependency 'GrowingUtils/TrackerCore', '0.0.7' + trackerCore.dependency 'GrowingUtils/TrackerCore', '1.0.0' trackerCore.source_files = 'GrowingTrackerCore/**/*{.h,.m,.c,.cpp,.mm}' trackerCore.public_header_files = 'GrowingTrackerCore/Public/*.h' trackerCore.ios.resource_bundles = {'GrowingAnalytics' => ['Resources/iOS/GrowingAnalytics.bundle/PrivacyInfo.xcprivacy']} @@ -50,7 +50,7 @@ GrowingAnalytics具备自动采集基本的用户行为事件,比如访问和 s.subspec 'AutotrackerCore' do |autotrackerCore| autotrackerCore.ios.deployment_target = '10.0' - autotrackerCore.dependency 'GrowingUtils/AutotrackerCore', '0.0.7' + autotrackerCore.dependency 'GrowingUtils/AutotrackerCore', '1.0.0' autotrackerCore.source_files = 'GrowingAutotrackerCore/**/*{.h,.m,.c,.cpp,.mm}' autotrackerCore.public_header_files = 'GrowingAutotrackerCore/Public/*.h' autotrackerCore.dependency 'GrowingAnalytics/TrackerCore', s.version.to_s diff --git a/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m b/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m index aafa77dca..e6fcbb157 100644 --- a/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m +++ b/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m @@ -25,23 +25,26 @@ @implementation UICollectionView (GrowingAutotracker) - (void)growing_setDelegate:(id)delegate { SEL selector = @selector(collectionView:didSelectItemAtIndexPath:); - id realDelegate = [GrowingULSwizzler realDelegate:delegate toSelector:selector]; + id realDelegate = [GrowingULSwizzle realDelegate:delegate toSelector:selector]; Class class = realDelegate.class; - if ([GrowingULSwizzler realDelegateClass:class respondsToSelector:selector]) { - void (^didSelectItemBlock)(id, SEL, id, id) = - ^(id view, SEL command, UICollectionView *collectionView, NSIndexPath *indexPath) { - if (collectionView && indexPath) { - UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; - if (cell) { - [GrowingViewClickProvider viewOnClick:cell]; - } - } - }; - - [GrowingULSwizzler growingul_swizzleSelector:selector - onClass:class - withBlock:didSelectItemBlock - named:@"growing_collectionView_didSelect"]; + if ([GrowingULSwizzle realDelegateClass:class respondsToSelector:selector]) { + static const void *key = &key; + GrowingULSwizzleInstanceMethod(class, + selector, + GUSWReturnType(void), + GUSWArguments(UICollectionView * collectionView, NSIndexPath * indexPath), + GUSWReplacement({ + GUSWCallOriginal(collectionView, indexPath); + if (collectionView && indexPath) { + UICollectionViewCell *cell = + [collectionView cellForItemAtIndexPath:indexPath]; + if (cell) { + [GrowingViewClickProvider viewOnClick:cell]; + } + } + }), + GrowingULSwizzleModeOncePerClassAndSuperclasses, + key); } [self growing_setDelegate:delegate]; diff --git a/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m b/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m index 720c48f01..ccf2b3fa1 100644 --- a/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m +++ b/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m @@ -25,22 +25,25 @@ @implementation UITableView (GrowingAutotracker) - (void)growing_setDelegate:(id)delegate { SEL selector = @selector(tableView:didSelectRowAtIndexPath:); - id realDelegate = [GrowingULSwizzler realDelegate:delegate toSelector:selector]; + id realDelegate = [GrowingULSwizzle realDelegate:delegate toSelector:selector]; Class class = realDelegate.class; - if ([GrowingULSwizzler realDelegateClass:class respondsToSelector:selector]) { - void (^didSelectBlock)(id, SEL, id, id) = - ^(id view, SEL command, UITableView *tableView, NSIndexPath *indexPath) { - if (tableView && indexPath) { - UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; - if (cell) { - [GrowingViewClickProvider viewOnClick:cell]; - } - } - }; - [GrowingULSwizzler growingul_swizzleSelector:selector - onClass:class - withBlock:didSelectBlock - named:@"growing_tableView_didSelect"]; + if ([GrowingULSwizzle realDelegateClass:class respondsToSelector:selector]) { + static const void *key = &key; + GrowingULSwizzleInstanceMethod(class, + selector, + GUSWReturnType(void), + GUSWArguments(UITableView * tableView, NSIndexPath * indexPath), + GUSWReplacement({ + GUSWCallOriginal(tableView, indexPath); + if (tableView && indexPath) { + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + if (cell) { + [GrowingViewClickProvider viewOnClick:cell]; + } + } + }), + GrowingULSwizzleModeOncePerClassAndSuperclasses, + key); } [self growing_setDelegate:delegate]; diff --git a/Package.swift b/Package.swift index 62dc77c5e..25fc2ec62 100644 --- a/Package.swift +++ b/Package.swift @@ -36,7 +36,7 @@ let package = Package( dependencies: [ .package( url: "https://github.com/growingio/growingio-sdk-ios-utilities.git", - "0.0.7" ..< "1.0.0" + "1.0.0" ..< "2.0.0" ), .package( url: "https://github.com/growingio/growingio-sdk-ios-performance-ext.git",