// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #import "FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h" #import #import FOUNDATION_STATIC_INLINE NSArray *FPRIvarObjectsForProxy(id proxy) { NSMutableArray *array = [NSMutableArray array]; // NSProxy subclasses can forward -class to a wrapped object, so use the runtime class. Class currentClass = object_getClass(proxy); while (currentClass && currentClass != [NSProxy class]) { unsigned int count = 0; Ivar *ivars = class_copyIvarList(currentClass, &count); if (ivars) { for (NSUInteger i = 0; i < count; i++) { const char *typeEncoding = ivar_getTypeEncoding(ivars[i]); if (typeEncoding && strncmp(typeEncoding, "@", 1) == 0) { id ivarObject = object_getIvar(proxy, ivars[i]); if (ivarObject) { [array addObject:ivarObject]; } } } free(ivars); } currentClass = class_getSuperclass(currentClass); } return array; } @implementation FPRProxyObjectHelper + (void)registerProxyObject:(id)proxy forSuperclass:(Class)superclass varFoundHandler:(void (^)(id ivar))varFoundHandler { NSArray *ivars = FPRIvarObjectsForProxy(proxy); for (id ivar in ivars) { if ([ivar isKindOfClass:superclass]) { varFoundHandler(ivar); } } } + (void)registerProxyObject:(id)proxy forProtocol:(Protocol *)protocol varFoundHandler:(void (^)(id ivar))varFoundHandler { NSArray *ivars = FPRIvarObjectsForProxy(proxy); for (id ivar in ivars) { if ([ivar conformsToProtocol:protocol]) { varFoundHandler(ivar); } } } @end