mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-11 22:55:59 +05:45
135 lines
4.8 KiB
Objective-C
135 lines
4.8 KiB
Objective-C
// 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
|