| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- // Copyright 2018 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 "GULSwizzlingCache.h"
- #import <objc/runtime.h>
- @interface GULSwizzlingCache ()
- - (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP;
- @end
- @implementation GULSwizzlingCache {
- /** A mapping from the new IMP to the original IMP. */
- CFMutableDictionaryRef _newToOriginalImps;
- /** A mapping from a Class and SEL (stored in a CFArray) to the original IMP that existed for it.
- */
- CFMutableDictionaryRef _originalImps;
- }
- + (instancetype)sharedInstance {
- static GULSwizzlingCache *sharedInstance;
- static dispatch_once_t token;
- dispatch_once(&token, ^{
- sharedInstance = [[GULSwizzlingCache alloc] init];
- });
- return sharedInstance;
- }
- - (instancetype)init {
- self = [super init];
- if (self) {
- _newToOriginalImps = CFDictionaryCreateMutable(kCFAllocatorDefault,
- 0, // Size.
- NULL, // Keys are pointers, so this is NULL.
- NULL); // Values are pointers so this is NULL.
- _originalImps = CFDictionaryCreateMutable(kCFAllocatorDefault,
- 0, // Size.
- &kCFTypeDictionaryKeyCallBacks, // Keys are CFArrays.
- NULL); // Values are pointers so this is NULL.
- }
- return self;
- }
- - (void)dealloc {
- CFRelease(_newToOriginalImps);
- CFRelease(_originalImps);
- }
- - (void)cacheCurrentIMP:(IMP)currentIMP
- forNewIMP:(IMP)newIMP
- forClass:(Class)aClass
- withSelector:(SEL)selector {
- IMP originalIMP = [self originalIMPOfCurrentIMP:currentIMP];
- CFDictionaryAddValue(_newToOriginalImps, newIMP, originalIMP);
- const void *classSELCArray[2] = {(__bridge void *)(aClass), selector};
- CFArrayRef classSELPair = CFArrayCreate(kCFAllocatorDefault, classSELCArray,
- 2, // Size.
- NULL); // Elements are pointers so this is NULL.
- CFDictionaryAddValue(_originalImps, classSELPair, originalIMP);
- CFRelease(classSELPair);
- }
- + (void)cacheCurrentIMP:(IMP)currentIMP
- forNewIMP:(IMP)newIMP
- forClass:(Class)aClass
- withSelector:(SEL)selector {
- [[GULSwizzlingCache sharedInstance] cacheCurrentIMP:currentIMP
- forNewIMP:newIMP
- forClass:aClass
- withSelector:selector];
- }
- - (IMP)cachedIMPForClass:(Class)aClass withSelector:(SEL)selector {
- const void *classSELCArray[2] = {(__bridge void *)(aClass), selector};
- CFArrayRef classSELPair = CFArrayCreate(kCFAllocatorDefault, classSELCArray,
- 2, // Size.
- NULL); // Elements are pointers so this is NULL.
- const void *returnedIMP = CFDictionaryGetValue(_originalImps, classSELPair);
- CFRelease(classSELPair);
- return (IMP)returnedIMP;
- }
- - (void)clearCacheForSwizzledIMP:(IMP)swizzledIMP selector:(SEL)selector aClass:(Class)aClass {
- CFDictionaryRemoveValue(_newToOriginalImps, swizzledIMP);
- const void *classSELCArray[2] = {(__bridge void *)(aClass), selector};
- CFArrayRef classSELPair = CFArrayCreate(kCFAllocatorDefault, classSELCArray,
- 2, // Size.
- NULL); // Elements are pointers so this is NULL.
- CFDictionaryRemoveValue(_originalImps, classSELPair);
- CFRelease(classSELPair);
- }
- - (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP {
- const void *returnedIMP = CFDictionaryGetValue(_newToOriginalImps, currentIMP);
- if (returnedIMP != NULL) {
- return (IMP)returnedIMP;
- } else {
- return currentIMP;
- }
- }
- + (IMP)originalIMPOfCurrentIMP:(IMP)currentIMP {
- return [[GULSwizzlingCache sharedInstance] originalIMPOfCurrentIMP:currentIMP];
- }
- #pragma mark - Helper methods for testing
- - (void)clearCache {
- CFDictionaryRemoveAllValues(_originalImps);
- CFDictionaryRemoveAllValues(_newToOriginalImps);
- }
- - (CFMutableDictionaryRef)originalImps {
- return _originalImps;
- }
- - (CFMutableDictionaryRef)newToOriginalImps {
- return _newToOriginalImps;
- }
- @end
|