what's new
* 动态启动图
* 动态聊天背景
* 支持8.0.1
* 更新越狱包8.0.1
* 更新已注入助手的8.0.1未签名包
* 更新越狱源安装包
This commit is contained in:
DKJone
2021-01-29 16:35:34 +08:00
parent 25a3f7f760
commit 888af8954e
125 changed files with 10144 additions and 40 deletions
@@ -0,0 +1,22 @@
// NSArray+VAPUtil.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
@interface NSArray (VAPUtil)
- (CGRect)hwd_rectValue;
@end
@@ -0,0 +1,37 @@
// NSArray+VAPUtil.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "NSArray+VAPUtil.h"
@implementation NSArray (VAPUtil)
- (CGRect)hwd_rectValue {
if (self.count < 4) {
return CGRectZero;
}
for (int i = 0; i < self.count; i++) {
id value = self[i];
if (i >= 4) {
break ;
}
if (![value isKindOfClass:[NSString class]] && ![value isKindOfClass:[NSNumber class]]) {
return CGRectZero;
}
}
return CGRectMake([self[0] floatValue], [self[1] floatValue], [self[2] floatValue], [self[3] floatValue]);
}
@end
@@ -0,0 +1,28 @@
// NSDictionary+VAPUtil.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
@interface NSDictionary (VAPUtil)
- (CGFloat)hwd_floatValue:(NSString *)key;
- (NSInteger)hwd_integerValue:(NSString *)key;
- (NSString *)hwd_stringValue:(NSString *)key;
- (NSDictionary *)hwd_dicValue:(NSString *)key;
- (NSArray *)hwd_arrValue:(NSString *)key;
@end
@@ -0,0 +1,71 @@
// NSDictionary+VAPUtil.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "NSDictionary+VAPUtil.h"
#define HWD_RETURN_VALUE(_type_, _default_) \
if (!key) return _default_; \
id value = self[key]; \
if (!value || value == [NSNull null]) return _default_; \
if ([value isKindOfClass:[NSNumber class]]) return ((NSNumber *)value)._type_; \
if ([value isKindOfClass:[NSString class]]) return ((NSString *)value)._type_; \
return _default_;
@implementation NSDictionary (VAPUtil)
- (CGFloat)hwd_floatValue:(NSString *)key {
HWD_RETURN_VALUE(floatValue, 0.0);
}
- (NSInteger)hwd_integerValue:(NSString *)key {
HWD_RETURN_VALUE(integerValue, 0);
}
- (NSString *)hwd_stringValue:(NSString *)key {
NSString *defaultValue = @"";
if (!key) return defaultValue;
id value = self[key];
if (!value || value == [NSNull null]) return defaultValue;
if ([value isKindOfClass:[NSString class]]) return value;
if ([value isKindOfClass:[NSNumber class]]) return ((NSNumber *)value).description;
return defaultValue;
}
- (NSDictionary *)hwd_dicValue:(NSString *)key {
if (!key) {
return nil;
}
id value = self[key];
if (![value isKindOfClass:[NSDictionary class]]) {
return nil;
}
return value;
}
- (NSArray *)hwd_arrValue:(NSString *)key {
if (!key) {
return nil;
}
id value = self[key];
if (![value isKindOfClass:[NSArray class]]) {
return nil;
}
return value;
}
@end
@@ -0,0 +1,54 @@
// NSNotificationCenter+VAPThreadSafe.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <Foundation/Foundation.h>
@interface NSNotificationCenter (VAPThreadSafe)
/**
该方法能够保证通知的执行和移除是线程安全的
不需要手动移除通知
(iOS9以下系统方法addObserver:selector:name:object:通常用法是不安全的。
@note 该方法适用于代替原来需要在dealloc内移除通知的场景
@param observer Object registering as an observer. This value must not be nil.
@param aSelector Selector that specifies the message the receiver sends observer to notify it of the notification posting. The method specified by aSelector must have one and only one argument (an instance of NSNotification).
@param aName The name of the notification for which to register the observer; that is, only notifications with this name are delivered to the observer.
If you pass nil, the notification center doesnt use a notifications name to decide whether to deliver it to the observer.
@param anObject The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer.
If you pass nil, the notification center doesnt use a notifications sender to decide whether to deliver it to the observer.
*/
- (void)hwd_addSafeObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject;
- (void)hwd_addWeakObserver:( id)weakObserver name:(NSNotificationName)aName usingBlock:(void (^)(NSNotification *note,id observer))block;
/**
1.设置接收通知的queue
2.调用- (void)addSafeObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject
@param observer Object registering as an observer. This value must not be nil.
@param aSelector Selector that specifies the message the receiver sends observer to notify it of the notification posting. The method specified by aSelector must have one and only one argument (an instance of NSNotification).
@param aName The name of the notification for which to register the observer; that is, only notifications with this name are delivered to the observer.
If you pass nil, the notification center doesnt use a notifications name to decide whether to deliver it to the observer.
@param anObject The object whose notifications the observer wants to receive; that is, only notifications sent by this sender are delivered to the observer.
If you pass nil, the notification center doesnt use a notifications sender to decide whether to deliver it to the observer.
@param queue The operation queue to which callbackoperation should be added.
If you pass nil, the block is run asynchronously on queue which hold by this notification.
*/
- (void)hwd_addSafeObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject queue:(NSOperationQueue *)queue;
@end
@@ -0,0 +1,89 @@
// NSNotificationCenter+ThreadSafe.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "NSNotificationCenter+VAPThreadSafe.h"
#import "QGVAPSafeMutableDictionary.h"
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
@interface NSObject (SafeNotification)
@property (nonatomic, strong) NSOperationQueue *notificationOperationQueue;
@end
@implementation NSObject (SafeNotification)
- (NSOperationQueue *)notificationOperationQueue {
@synchronized (self) {
NSOperationQueue *queue = objc_getAssociatedObject(self, @"notificationOperationQueue");
if (!queue) {
queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
self.notificationOperationQueue = queue;
}
return queue;
}
}
- (void)setNotificationOperationQueue:(NSOperationQueue *)notificationOperationQueue {
@synchronized (self) {
objc_setAssociatedObject(self, @"notificationOperationQueue", notificationOperationQueue, OBJC_ASSOCIATION_RETAIN);
}
}
@end
@implementation NSNotificationCenter (VAPThreadSafe)
- (void)hwd_addSafeObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject {
double sysVersion = [[[UIDevice currentDevice] systemVersion] doubleValue];;
if (sysVersion >= 9.0) {
return [self addObserver:observer selector:aSelector name:aName object:anObject];
}
__weak typeof(observer) weakObserver = observer;
__block NSObject *blockObserver = [self addObserverForName:aName object:anObject queue:aName.notificationOperationQueue usingBlock:^(NSNotification * _Nonnull note) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
__strong __typeof__(weakObserver) strongObserver = weakObserver;
[strongObserver performSelector:aSelector withObject:note];
#pragma clang diagnostic pop
if (!weakObserver) {
[[NSNotificationCenter defaultCenter] removeObserver:blockObserver];
blockObserver = nil;
}
}];
}
- (void)hwd_addWeakObserver:( id)Observer name:(NSNotificationName)aName usingBlock:(void (^)(NSNotification *note,id observer))block{
__weak id weakObserver=Observer;
__block NSObject *blockObserver = [self addObserverForName:aName object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
__strong id strongObserver = weakObserver;
if(!weakObserver ){
[[NSNotificationCenter defaultCenter] removeObserver:blockObserver];
blockObserver = nil;
}else{
block(note,strongObserver);
}
}];
}
- (void)hwd_addSafeObserver:(id)observer selector:(SEL)aSelector name:(NSNotificationName)aName object:(id)anObject queue:(NSOperationQueue *)queue {
aName.notificationOperationQueue = queue;
[self hwd_addSafeObserver:observer selector:aSelector name:aName object:anObject];
}
@end
@@ -0,0 +1,26 @@
// UIColor+VAPUtil.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIColor (VAPUtil)
+ (instancetype)hwd_colorWithHexString:(NSString *)hexStr;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,66 @@
// UIColor+VAPUtil.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "UIColor+VAPUtil.h"
@implementation UIColor (VAPUtil)
static inline NSUInteger hwd_hexStrToInt(NSString *str) {
uint32_t result = 0;
sscanf([str UTF8String], "%X", &result);
return result;
}
static BOOL hwd_hexStrToRGBA(NSString *str,
CGFloat *r, CGFloat *g, CGFloat *b, CGFloat *a) {
NSCharacterSet *cset = [NSCharacterSet whitespaceAndNewlineCharacterSet];
str = [[str stringByTrimmingCharactersInSet:cset] uppercaseString];
if ([str hasPrefix:@"#"]) {
str = [str substringFromIndex:1];
} else if ([str hasPrefix:@"0X"]) {
str = [str substringFromIndex:2];
}
NSUInteger length = [str length];
//RGB||RGBA||RRGGBB||RRGGBBAA
if (length != 3 && length != 4 && length != 6 && length != 8) {
return NO;
}
if (length < 5) {
*r = hwd_hexStrToInt([str substringWithRange:NSMakeRange(0, 1)]) / 255.0f;
*g = hwd_hexStrToInt([str substringWithRange:NSMakeRange(1, 1)]) / 255.0f;
*b = hwd_hexStrToInt([str substringWithRange:NSMakeRange(2, 1)]) / 255.0f;
if (length == 4) *a = hwd_hexStrToInt([str substringWithRange:NSMakeRange(3, 1)]) / 255.0f;
else *a = 1;
} else {
*r = hwd_hexStrToInt([str substringWithRange:NSMakeRange(0, 2)]) / 255.0f;
*g = hwd_hexStrToInt([str substringWithRange:NSMakeRange(2, 2)]) / 255.0f;
*b = hwd_hexStrToInt([str substringWithRange:NSMakeRange(4, 2)]) / 255.0f;
if (length == 8) *a = hwd_hexStrToInt([str substringWithRange:NSMakeRange(6, 2)]) / 255.0f;
else *a = 1;
}
return YES;
}
+ (instancetype)hwd_colorWithHexString:(NSString *)hexStr {
CGFloat r, g, b, a;
if (hwd_hexStrToRGBA(hexStr, &r, &g, &b, &a)) {
return [UIColor colorWithRed:r green:g blue:b alpha:a];
}
return nil;
}
@end
@@ -0,0 +1,45 @@
// UIDevice+VAPUtil.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
#import <Metal/Metal.h>
#ifndef kHWDSystemVersion
#define kHWDSystemVersion [UIDevice systemVersionNum]
#endif
#ifndef kHWDiOS9Later
#define kHWDiOS9Later (kHWDSystemVersion >= 9)
#endif
#define kDefaultMTLResourceOption getDefaultMTLResourceOption()
#ifdef __cplusplus
extern "C" {
#endif
MTLResourceOptions getDefaultMTLResourceOption(void);
#ifdef __cplusplus
}
#endif
NS_ASSUME_NONNULL_BEGIN
@interface UIDevice (VAPUtil)
+ (double)systemVersionNum;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,38 @@
// UIDevice+VAPUtil.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "UIDevice+VAPUtil.h"
MTLResourceOptions getDefaultMTLResourceOption() {
if (@available(iOS 9.0, *)) {
return MTLResourceStorageModeShared;
} else {
return MTLResourceCPUCacheModeDefaultCache;
}
}
@implementation UIDevice (VAPUtil)
+ (double)systemVersionNum {
static double version;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
version = [UIDevice currentDevice].systemVersion.doubleValue;
});
return version;
}
@end
@@ -0,0 +1,26 @@
// UIGestureRecognizer+VAPUtil.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
@interface UIGestureRecognizer (VAPUtil)
- (instancetype)initWithVapActionBlock:(void (^)(id sender))block;
- (void)addVapActionBlock:(void (^)(id sender))block;
- (void)removeAllVapActionBlocks;
@end
@@ -0,0 +1,84 @@
// UIGestureRecognizer+VAPUtil.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "UIGestureRecognizer+VAPUtil.h"
#import <objc/runtime.h>
#import "QGVAPSafeMutableArray.h"
static const int vap_block_key;
@interface _VAPUIGestureRecognizerBlockTarget : NSObject
@property (nonatomic, copy) void (^block)(id sender);
- (id)initWithBlock:(void (^)(id sender))block;
- (void)invoke:(id)sender;
@end
@implementation _VAPUIGestureRecognizerBlockTarget
- (id)initWithBlock:(void (^)(id sender))block{
if (self = [super init]) {
_block = [block copy];
}
return self;
}
- (void)invoke:(id)sender {
if (_block) _block(sender);
}
@end
@implementation UIGestureRecognizer (VAPUtil)
- (instancetype)initWithVapActionBlock:(void (^)(id sender))block {
if (self = [self init]) {
[self addVapActionBlock:block];
}
return self;
}
- (void)addVapActionBlock:(void (^)(id sender))block {
_VAPUIGestureRecognizerBlockTarget *target = [[_VAPUIGestureRecognizerBlockTarget alloc] initWithBlock:block];
[self addTarget:target action:@selector(invoke:)];
NSMutableArray *targets = [self _vap_allUIGestureRecognizerBlockTargets];
[targets addObject:target];
}
- (NSMutableArray *)_vap_allUIGestureRecognizerBlockTargets {
NSMutableArray *targets = objc_getAssociatedObject(self, &vap_block_key);
if (!targets) {
targets = [QGVAPSafeMutableArray new];
objc_setAssociatedObject(self, &vap_block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return targets;
}
- (void)removeAllVapActionBlocks {
NSMutableArray *targets = [self _vap_allUIGestureRecognizerBlockTargets];
[targets enumerateObjectsUsingBlock:^(id target, NSUInteger idx, BOOL *stop) {
[self removeTarget:target action:@selector(invoke:)];
}];
[targets removeAllObjects];
}
@end
@@ -0,0 +1,25 @@
// UIView+MP4HWDecode.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
#import "UIView+VAP.h"
NS_ASSUME_NONNULL_BEGIN
@interface UIView (MP4HWDecode)
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,20 @@
// UIView+MP4HWDecode.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "UIView+MP4HWDecode.h"
@implementation UIView (MP4HWDecode)
@end
@@ -0,0 +1,65 @@
// QGVAPLogger.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <Foundation/Foundation.h>
#define kQGVAPModuleCommon @"kQGVAPModuleCommon"
NS_ASSUME_NONNULL_BEGIN
#define VAP_Logger(level, module, format, ...) if(external_VAP_Logger)external_VAP_Logger(level, __FILE__, __LINE__, __FUNCTION__, module, format, ##__VA_ARGS__); else internal_VAP_Logger_handler(level, __FILE__, __LINE__, __FUNCTION__, module, format, ##__VA_ARGS__);
#define VAP_Error(module, format, ...) VAP_Logger(VAPLogLevelError, module, format, ##__VA_ARGS__)
#define VAP_Event(module, format, ...) VAP_Logger(VAPLogLevelEvent, module, format, ##__VA_ARGS__)
#define VAP_Warn(module, format, ...) VAP_Logger(VAPLogLevelWarn, module, format, ##__VA_ARGS__)
#define VAP_Info(module, format, ...) VAP_Logger(VAPLogLevelInfo, module, format, ##__VA_ARGS__)
#define VAP_Debug(module, format, ...) VAP_Logger(VAPLogLevelDebug, module, format, ##__VA_ARGS__)
typedef enum {
VAPLogLevelAll = 0,
VAPLogLevelDebug, // Detailed information on the flow through the system.
VAPLogLevelInfo, // Interesting runtime events (startup/shutdown), should be conservative and keep to a minimum.
VAPLogLevelEvent,
VAPLogLevelWarn, // Other runtime situations that are undesirable or unexpected, but not necessarily "wrong".
VAPLogLevelError, // Other runtime errors or unexpected conditions.
VAPLogLevelFatal, // Severe errors that cause premature termination.
VAPLogLevelNone, // Special level used to disable all log messages.
} VAPLogLevel;
typedef VAPLogLevel HWDLogLevel;
//void qg_VAP_Logger(VAPLogLevel level, const char* file, int line, const char* func, NSString *MODULE, NSString *format, ...);
typedef void (*QGVAPLoggerFunc)(VAPLogLevel, const char*, int, const char*, NSString *, NSString *, ...);
#if defined __cplusplus
extern "C" {
#endif
extern QGVAPLoggerFunc external_VAP_Logger;
void internal_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const char* func, NSString *module, NSString *format, ...);
#if defined __cplusplus
};
#endif
@interface QGVAPLogger : NSObject
+ (void)registerExternalLog:(QGVAPLoggerFunc)externalLog;
+ (void)log:(VAPLogLevel)level file:(NSString *)file line:(NSInteger)line func:(NSString *)func module:(NSString *)module message:(NSString *)message;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,53 @@
// QGVAPLogger.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "QGVAPLogger.h"
QGVAPLoggerFunc external_VAP_Logger;
@implementation QGVAPLogger
#pragma mark - Extenral log
void internal_VAP_Logger_handler(VAPLogLevel level, const char* file, int line, const char* func, NSString *module, NSString *format, ...) {
#ifdef DEBUG
va_list arg_list;
va_start (arg_list, format);
NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
va_end(arg_list);
file = [NSString stringWithUTF8String:file].lastPathComponent.UTF8String;
NSLog(@"<%@> %s(%@):%s [%@] - %@",@(level), file, @(line), func, module, formattedString);
#endif
}
+ (void)registerExternalLog:(QGVAPLoggerFunc)externalLog {
external_VAP_Logger = externalLog;
}
+ (void)log:(VAPLogLevel)level file:(NSString *)file line:(NSInteger)line func:(NSString *)func module:(NSString *)module message:(NSString *)message {
if ([message containsString:@"%"]) {
//此处是为了兼容%进入formmat之后的crash风险
[message stringByReplacingOccurrencesOfString:@"%" withString:@""];
}
if (external_VAP_Logger) {
external_VAP_Logger(level, file.UTF8String, (int)line, func.UTF8String, module, message);
} else {
internal_VAP_Logger_handler(level, file.UTF8String, (int)line, func.UTF8String, module, message);
}
}
@end
@@ -0,0 +1,24 @@
// QGVAPMetalShaderFunctionLoader.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <Foundation/Foundation.h>
#import <MetalKit/MetalKit.h>
@interface QGVAPMetalShaderFunctionLoader : NSObject
- (instancetype)initWithDevice:(id<MTLDevice>)device;
- (id<MTLFunction>)loadFunctionWithName:(NSString *)funcName;
@end
@@ -0,0 +1,92 @@
// QGVAPMetalShaderFunctionLoader.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "QGVAPMetalShaderFunctionLoader.h"
#import "QGHWDMetalShaderSourceDefine.h"
#import "QGHWDShaderTypes.h"
#import "QGVAPLogger.h"
@interface QGVAPMetalShaderFunctionLoader () {
BOOL _alreadyLoadDefaultLibrary;
BOOL _alreadyLoadHWDLibrary;
}
@property (nonatomic, strong) id<MTLDevice> device;
@property (nonatomic, strong) id<MTLLibrary> defaultLibrary;
@property (nonatomic, strong) id<MTLLibrary> hwdLibrary;
@end
@implementation QGVAPMetalShaderFunctionLoader
- (instancetype)initWithDevice:(id<MTLDevice>)device {
if (self = [super init]) {
_device = device;
}
return self;
}
- (id<MTLFunction>)loadFunctionWithName:(NSString *)funcName {
id<MTLFunction> program = nil;
[self loadDefaultLibraryIfNeed];
program = [self.defaultLibrary newFunctionWithName:funcName];
//没有找到defaultLibrary文件 || defaultLibrary中不包含对应的fucntion
if (!program) {
[self loadHWDLibraryIfNeed];
program = [self.hwdLibrary newFunctionWithName:funcName];
}
return program;
}
- (void)loadDefaultLibraryIfNeed {
if (self.defaultLibrary || _alreadyLoadDefaultLibrary) {
return ;
}
NSBundle *bundle = [NSBundle bundleForClass:self.class];
NSString *metalLibPath = [bundle pathForResource:@"default" ofType:@"metallib"];
if (metalLibPath.length == 0) {
return ;
}
NSError *error = nil;
id<MTLLibrary> defaultLibrary = [self.device newLibraryWithFile:metalLibPath error:&error];
if (!defaultLibrary || error) {
VAP_Error(kQGVAPModuleCommon, @"loadDefaultLibrary error!:%@", error);
return ;
}
self.defaultLibrary = defaultLibrary;
_alreadyLoadDefaultLibrary = YES;
}
- (void)loadHWDLibraryIfNeed {
if (self.hwdLibrary || _alreadyLoadHWDLibrary) {
return ;
}
NSError *error = nil;
NSString *sourceString = [NSString stringWithFormat:@"%@%@%@", kQGHWDMetalShaderSourceImports, kQGHWDMetalShaderTypeDefines, kQGHWDMetalShaderSourceString];
id<MTLLibrary> hwdLibrary = [self.device newLibraryWithSource:sourceString options:nil error:&error];
if (!hwdLibrary || error) {
VAP_Error(kQGVAPModuleCommon, @"loadHWDLibrary error!:%@", error);
return ;
}
self.hwdLibrary = hwdLibrary;
_alreadyLoadHWDLibrary = YES;
}
@end
@@ -0,0 +1,46 @@
// QGVAPMetalUtil.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <UIKit/UIKit.h>
UIKIT_EXTERN NSString *const kHWDAttachmentVertexFunctionName;
UIKIT_EXTERN NSString *const kVAPAttachmentVertexFunctionName;
UIKIT_EXTERN NSString *const kVAPAttachmentFragmentFunctionName;
UIKIT_EXTERN NSString *const kVAPVertexFunctionName;
UIKIT_EXTERN NSString *const kVAPYUVFragmentFunctionName;
UIKIT_EXTERN NSString *const kVAPMaskFragmentFunctionName;
UIKIT_EXTERN NSString *const kVAPMaskBlurFragmentFunctionName;
extern float const kVAPMTLVerticesIdentity[16];
extern float const kVAPMTLTextureCoordinatesIdentity[8];
extern float const kVAPMTLTextureCoordinatesFor90[8];
#ifdef __cplusplus
extern "C" {
#endif
void genMTLVertices(CGRect rect, CGSize containerSize, float vertices[16], BOOL reverse); //生成顶点坐标
void genMTLTextureCoordinates(CGRect rect, CGSize containerSize, float coordinates[8], BOOL reverse, NSInteger degree); //生成纹理坐标
void replaceArrayElements(float arr0[], float arr1[], int size); //arr0[0...(size-1)] <- arr1[0...(size-1)]
CGSize vapSourceSizeForCenterFull(CGSize sourceSize, CGSize renderSize);
CGRect vapRectForCenterFull(CGSize sourceSize, CGSize renderSize);
CGRect vapRectWithContentModeInsideRect(CGRect boundingRect, CGSize aspectRatio, UIViewContentMode contentMode);
#ifdef __cplusplus
}
#endif
@interface QGVAPMetalUtil : NSObject
@end
@@ -0,0 +1,190 @@
// QGVAPMetalUtil.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "QGVAPMetalUtil.h"
#import <AVFoundation/AVFoundation.h>
#import "QGVAPLogger.h"
#import <UIKit/UIKit.h>
NSString *const kVAPAttachmentVertexFunctionName = @"vapAttachment_vertexShader";
NSString *const kVAPAttachmentFragmentFunctionName = @"vapAttachment_FragmentShader";
NSString *const kVAPVertexFunctionName = @"vap_vertexShader";
NSString *const kVAPYUVFragmentFunctionName = @"vap_yuvFragmentShader";
NSString *const kVAPMaskFragmentFunctionName = @"vap_maskFragmentShader";
NSString *const kVAPMaskBlurFragmentFunctionName = @"vap_maskBlurFragmentShader";
float const kVAPMTLVerticesIdentity[16] = {-1.0, -1.0, 0.0, 1.0, -1.0, 1.0, 0.0, 1.0, 1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0};
float const kVAPMTLTextureCoordinatesIdentity[8] = {0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0};
float const kVAPMTLTextureCoordinatesFor90[8] = {0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0};
void replaceArrayElements(float arr0[], float arr1[], int size) {
if ((arr0 == NULL || arr1 == NULL) && size > 0) {
assert(0);
}
if (size < 0) {
assert(0);
}
for (int i = 0; i < size; i++) {
arr0[i] = arr1[i];
}
}
//倒N形
void genMTLVertices(CGRect rect, CGSize containerSize, float vertices[16], BOOL reverse) {
if (vertices == NULL) {
VAP_Error(kQGVAPModuleCommon, @"generateMTLVertices params illegal.");
assert(0);
return ;
}
if (containerSize.width <= 0 || containerSize.height <= 0) {
VAP_Error(kQGVAPModuleCommon, @"generateMTLVertices params containerSize illegal.");
assert(0);
return ;
}
float originX, originY, width, height;
originX = -1+2*rect.origin.x/containerSize.width;
originY = 1-2*rect.origin.y/containerSize.height;
width = 2*rect.size.width/containerSize.width;
height = 2*rect.size.height/containerSize.height;
if (reverse) {
float tempVertices[] = {originX, originY-height, 0.0, 1.0, originX, originY, 0.0, 1.0, originX+width, originY-height, 0.0, 1.0, originX+width, originY, 0.0, 1.0};
replaceArrayElements(vertices, tempVertices, 16);
return ;
}
float tempVertices[] = {originX, originY, 0.0, 1.0, originX, originY-height, 0.0, 1.0, originX+width, originY, 0.0, 1.0 , originX+width, originY-height, 0.0, 1.0};
replaceArrayElements(vertices, tempVertices, 16);
}
//N形
void genMTLTextureCoordinates(CGRect rect, CGSize containerSize, float coordinates[8], BOOL reverse, NSInteger degree) {
//degree预留字段,支持旋转纹理
if (coordinates == NULL) {
VAP_Error(kQGVAPModuleCommon, @"generateMTLTextureCoordinates params coordinates illegal.");
assert(0);
return ;
}
if (containerSize.width <= 0 || containerSize.height <= 0) {
VAP_Error(kQGVAPModuleCommon, @"generateMTLTextureCoordinates params containerSize illegal.");
assert(0);
return ;
}
float originX, originY, width, height;
originX = rect.origin.x/containerSize.width;
originY = rect.origin.y/containerSize.height;
width = rect.size.width/containerSize.width;
height = rect.size.height/containerSize.height;
if (reverse) {
float tempCoordintes[] = {originX, originY, originX, originY+height , originX+width, originY,originX+width, originY+height};
replaceArrayElements(coordinates, tempCoordintes, 8);
return ;
}
float tempCoordintes[] = {originX, originY+height, originX, originY, originX+width, originY+height, originX+width, originY};
replaceArrayElements(coordinates, tempCoordintes, 8);
}
CGSize vapSourceSizeForCenterFull(CGSize sourceSize, CGSize renderSize) {
//source大小完全包含render大小,直接返回中间部分
if (sourceSize.width >= renderSize.width && sourceSize.height >= renderSize.height) {
return sourceSize;
}
CGRect rectForAspectFill = vapRectWithContentModeInsideRect(CGRectMake(0, 0, renderSize.width, renderSize.height), sourceSize, UIViewContentModeScaleAspectFill);
return rectForAspectFill.size;
}
CGRect vapRectForCenterFull(CGSize sourceSize, CGSize renderSize) {
//source大小完全包含render大小,直接返回中间部分
if (sourceSize.width >= renderSize.width && sourceSize.height >= renderSize.height) {
return CGRectMake((sourceSize.width-renderSize.width)/2.0, (sourceSize.height-renderSize.height)/2.0, renderSize.width, renderSize.height);
}
CGRect rectForAspectFill = vapRectWithContentModeInsideRect(CGRectMake(0, 0, renderSize.width, renderSize.height), sourceSize, UIViewContentModeScaleAspectFill);
CGRect intersection = CGRectMake(-rectForAspectFill.origin.x, -rectForAspectFill.origin.y, renderSize.width, renderSize.height);
return intersection;
}
CGRect vapRectWithContentModeInsideRect(CGRect boundingRect, CGSize aspectRatio, UIViewContentMode contentMode) {
if (aspectRatio.width <= 0 || aspectRatio.height <= 0) {
return boundingRect;
}
CGRect desRect = CGRectZero;
switch (contentMode) {
case UIViewContentModeScaleToFill: {
desRect = boundingRect;
}
break;
case UIViewContentModeScaleAspectFit: {
desRect = AVMakeRectWithAspectRatioInsideRect(aspectRatio, boundingRect);
}
break;
case UIViewContentModeScaleAspectFill: {
CGFloat ratio = MAX(CGRectGetWidth(boundingRect)/aspectRatio.width, CGRectGetHeight(boundingRect)/aspectRatio.height);
CGSize contentSize = CGSizeMake(aspectRatio.width*ratio, aspectRatio.height*ratio);
desRect = CGRectMake(boundingRect.origin.x+(CGRectGetWidth(boundingRect)-contentSize.width)/2.0, boundingRect.origin.y+(CGRectGetHeight(boundingRect)-contentSize.height)/2.0, contentSize.width, contentSize.height);
}
break;
case UIViewContentModeCenter: {
desRect = CGRectMake(boundingRect.origin.x+(CGRectGetWidth(boundingRect)-aspectRatio.width)/2.0, boundingRect.origin.y+(CGRectGetHeight(boundingRect)-aspectRatio.height)/2.0, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeTop: {
desRect = CGRectMake(boundingRect.origin.x+(CGRectGetWidth(boundingRect)-aspectRatio.width)/2.0, boundingRect.origin.y, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeBottom: {
desRect = CGRectMake(boundingRect.origin.x+(CGRectGetWidth(boundingRect)-aspectRatio.width)/2.0, boundingRect.origin.y+CGRectGetHeight(boundingRect)-aspectRatio.height, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeLeft: {
desRect = CGRectMake(boundingRect.origin.x, boundingRect.origin.y+(CGRectGetHeight(boundingRect)-aspectRatio.height)/2.0, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeRight: {
desRect = CGRectMake(boundingRect.origin.x+CGRectGetWidth(boundingRect)-aspectRatio.width, boundingRect.origin.y+(CGRectGetHeight(boundingRect)-aspectRatio.height)/2.0, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeTopLeft: {
desRect = CGRectMake(boundingRect.origin.x, boundingRect.origin.y, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeTopRight: {
desRect = CGRectMake(boundingRect.origin.x+CGRectGetWidth(boundingRect)-aspectRatio.width, boundingRect.origin.y, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeBottomLeft: {
desRect = CGRectMake(boundingRect.origin.x, boundingRect.origin.y+CGRectGetHeight(boundingRect)-aspectRatio.height, aspectRatio.width, aspectRatio.height);
}
break;
case UIViewContentModeBottomRight: {
desRect = CGRectMake(boundingRect.origin.x+CGRectGetWidth(boundingRect)-aspectRatio.width, boundingRect.origin.y+CGRectGetHeight(boundingRect)-aspectRatio.height, aspectRatio.width, aspectRatio.height);
}
break;
default:
break;
}
return desRect;
}
@implementation QGVAPMetalUtil
@end
@@ -0,0 +1,28 @@
// QGVAPSafeMutableArray.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <Foundation/Foundation.h>
/**
This class inherits from NSMutableArray,make it tread safe and allow Recursive lock.
@discussion access performance would lower than NSMutableArray, or using semaphore but equal to @sychronized.
@warning Fast enumerate and enumerator are not thread safe
*/
@interface QGVAPSafeMutableArray : NSMutableArray
@end
@@ -0,0 +1,384 @@
// QGVAPSafeMutableArray.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "QGVAPSafeMutableArray.h"
#define VAP_INIT(...) self = super.init; \
if (!self) return nil; \
__VA_ARGS__; \
if (!_arr) return nil; \
_lock = [[NSRecursiveLock alloc] init]; \
return self;
#define VAP_LOCK(...) [_lock lock]; \
__VA_ARGS__; \
[_lock unlock];
@interface QGVAPSafeMutableArray (){
NSMutableArray *_arr;
NSRecursiveLock *_lock;
}
@end
@implementation QGVAPSafeMutableArray
#pragma mark - init
-(instancetype)init{
VAP_INIT(_arr = [NSMutableArray new]);
}
-(instancetype)initWithCapacity:(NSUInteger)numItems{
VAP_INIT(_arr = [[NSMutableArray alloc] initWithCapacity:numItems]);
}
-(instancetype)initWithArray:(NSArray *)array{
VAP_INIT(_arr = [[NSMutableArray alloc] initWithArray:array]);
}
-(instancetype)initWithObjects:(id _Nonnull const [])objects count:(NSUInteger)cnt{
VAP_INIT(_arr = [[NSMutableArray alloc] initWithObjects:objects count:cnt]);
}
- (instancetype)initWithContentsOfFile:(NSString *)path {
VAP_INIT(_arr = [[NSMutableArray alloc] initWithContentsOfFile:path]);
}
- (instancetype)initWithContentsOfURL:(NSURL *)url {
VAP_INIT(_arr = [[NSMutableArray alloc] initWithContentsOfURL:url]);
}
#pragma mark - methods
- (NSUInteger)count {
VAP_LOCK(NSUInteger count = _arr.count); return count;
}
- (id)objectAtIndex:(NSUInteger)index {
VAP_LOCK(id obj = [_arr objectAtIndex:index]); return obj;
}
- (NSArray *)arrayByAddingObject:(id)anObject {
VAP_LOCK(NSArray * arr = [_arr arrayByAddingObject:anObject]); return arr;
}
- (NSArray *)arrayByAddingObjectsFromArray:(NSArray *)otherArray {
VAP_LOCK(NSArray * arr = [_arr arrayByAddingObjectsFromArray:otherArray]); return arr;
}
- (NSString *)componentsJoinedByString:(NSString *)separator {
VAP_LOCK(NSString * str = [_arr componentsJoinedByString:separator]); return str;
}
- (BOOL)containsObject:(id)anObject {
VAP_LOCK(BOOL c = [_arr containsObject:anObject]); return c;
}
- (NSString *)description {
VAP_LOCK(NSString * d = _arr.description); return d;
}
- (NSString *)descriptionWithLocale:(id)locale {
VAP_LOCK(NSString * d = [_arr descriptionWithLocale:locale]); return d;
}
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level {
VAP_LOCK(NSString * d = [_arr descriptionWithLocale:locale indent:level]); return d;
}
- (id)firstObjectCommonWithArray:(NSArray *)otherArray {
VAP_LOCK(id o = [_arr firstObjectCommonWithArray:otherArray]); return o;
}
- (void)getObjects:(id __unsafe_unretained[])objects range:(NSRange)range {
VAP_LOCK([_arr getObjects:objects range:range]);
}
- (NSUInteger)indexOfObject:(id)anObject {
VAP_LOCK(NSUInteger i = [_arr indexOfObject:anObject]); return i;
}
- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range {
VAP_LOCK(NSUInteger i = [_arr indexOfObject:anObject inRange:range]); return i;
}
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject {
VAP_LOCK(NSUInteger i = [_arr indexOfObjectIdenticalTo:anObject]); return i;
}
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject inRange:(NSRange)range {
VAP_LOCK(NSUInteger i = [_arr indexOfObjectIdenticalTo:anObject inRange:range]); return i;
}
- (id)firstObject {
VAP_LOCK(id o = _arr.firstObject); return o;
}
- (id)lastObject {
VAP_LOCK(id o = _arr.lastObject); return o;
}
- (NSEnumerator *)objectEnumerator {
VAP_LOCK(NSEnumerator * e = [_arr objectEnumerator]); return e;
}
- (NSEnumerator *)reverseObjectEnumerator {
VAP_LOCK(NSEnumerator * e = [_arr reverseObjectEnumerator]); return e;
}
- (NSData *)sortedArrayHint {
VAP_LOCK(NSData * d = [_arr sortedArrayHint]); return d;
}
- (NSArray *)sortedArrayUsingFunction:(__attribute__((noescape)) NSInteger (*)(id, id, void *))comparator context:(void *)context {
VAP_LOCK(NSArray * arr = [_arr sortedArrayUsingFunction:comparator context:context]) return arr;
}
- (NSArray *)sortedArrayUsingFunction:(__attribute__((noescape)) NSInteger (*)(id, id, void *))comparator context:(void *)context hint:(NSData *)hint {
VAP_LOCK(NSArray * arr = [_arr sortedArrayUsingFunction:comparator context:context hint:hint]); return arr;
}
- (NSArray *)sortedArrayUsingSelector:(SEL)comparator {
VAP_LOCK(NSArray * arr = [_arr sortedArrayUsingSelector:comparator]); return arr;
}
- (NSArray *)subarrayWithRange:(NSRange)range {
VAP_LOCK(NSArray * arr = [_arr subarrayWithRange:range]) return arr;
}
- (void)makeObjectsPerformSelector:(SEL)aSelector {
VAP_LOCK([_arr makeObjectsPerformSelector:aSelector]);
}
- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)argument {
VAP_LOCK([_arr makeObjectsPerformSelector:aSelector withObject:argument]);
}
- (NSArray *)objectsAtIndexes:(NSIndexSet *)indexes {
VAP_LOCK(NSArray * arr = [_arr objectsAtIndexes:indexes]); return arr;
}
- (id)objectAtIndexedSubscript:(NSUInteger)idx {
VAP_LOCK(id o = [_arr objectAtIndexedSubscript:idx]); return o;
}
- (void)enumerateObjectsUsingBlock:(__attribute__((noescape)) void (^)(id obj, NSUInteger idx, BOOL *stop))block {
VAP_LOCK([_arr enumerateObjectsUsingBlock:block]);
}
- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(__attribute__((noescape)) void (^)(id obj, NSUInteger idx, BOOL *stop))block {
VAP_LOCK([_arr enumerateObjectsWithOptions:opts usingBlock:block]);
}
- (void)enumerateObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts usingBlock:(__attribute__((noescape)) void (^)(id obj, NSUInteger idx, BOOL *stop))block {
VAP_LOCK([_arr enumerateObjectsAtIndexes:s options:opts usingBlock:block]);
}
- (NSUInteger)indexOfObjectPassingTest:(__attribute__((noescape)) BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
VAP_LOCK(NSUInteger i = [_arr indexOfObjectPassingTest:predicate]); return i;
}
- (NSUInteger)indexOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(__attribute__((noescape)) BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
VAP_LOCK(NSUInteger i = [_arr indexOfObjectWithOptions:opts passingTest:predicate]); return i;
}
- (NSUInteger)indexOfObjectAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(__attribute__((noescape)) BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
VAP_LOCK(NSUInteger i = [_arr indexOfObjectAtIndexes:s options:opts passingTest:predicate]); return i;
}
- (NSIndexSet *)indexesOfObjectsPassingTest:(__attribute__((noescape)) BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
VAP_LOCK(NSIndexSet * i = [_arr indexesOfObjectsPassingTest:predicate]); return i;
}
- (NSIndexSet *)indexesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(__attribute__((noescape)) BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
VAP_LOCK(NSIndexSet * i = [_arr indexesOfObjectsWithOptions:opts passingTest:predicate]); return i;
}
- (NSIndexSet *)indexesOfObjectsAtIndexes:(NSIndexSet *)s options:(NSEnumerationOptions)opts passingTest:(__attribute__((noescape)) BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate {
VAP_LOCK(NSIndexSet * i = [_arr indexesOfObjectsAtIndexes:s options:opts passingTest:predicate]); return i;
}
- (NSArray *)sortedArrayUsingComparator:(__attribute__((noescape)) NSComparator)cmptr {
VAP_LOCK(NSArray * a = [_arr sortedArrayUsingComparator:cmptr]); return a;
}
- (NSArray *)sortedArrayWithOptions:(NSSortOptions)opts usingComparator:(__attribute__((noescape)) NSComparator)cmptr {
VAP_LOCK(NSArray * a = [_arr sortedArrayWithOptions:opts usingComparator:cmptr]); return a;
}
- (NSUInteger)indexOfObject:(id)obj inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(__attribute__((noescape)) NSComparator)cmp {
VAP_LOCK(NSUInteger i = [_arr indexOfObject:obj inSortedRange:r options:opts usingComparator:cmp]); return i;
}
#pragma mark - mutable
- (void)addObject:(id)anObject {
VAP_LOCK([_arr addObject:anObject]);
}
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index {
VAP_LOCK([_arr insertObject:anObject atIndex:index]);
}
- (void)removeLastObject {
VAP_LOCK([_arr removeLastObject]);
}
- (void)removeObjectAtIndex:(NSUInteger)index {
VAP_LOCK([_arr removeObjectAtIndex:index]);
}
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
VAP_LOCK([_arr replaceObjectAtIndex:index withObject:anObject]);
}
- (void)addObjectsFromArray:(NSArray *)otherArray {
VAP_LOCK([_arr addObjectsFromArray:otherArray]);
}
- (void)exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2 {
VAP_LOCK([_arr exchangeObjectAtIndex:idx1 withObjectAtIndex:idx2]);
}
- (void)removeAllObjects {
VAP_LOCK([_arr removeAllObjects]);
}
- (void)removeObject:(id)anObject inRange:(NSRange)range {
VAP_LOCK([_arr removeObject:anObject inRange:range]);
}
- (void)removeObject:(id)anObject {
VAP_LOCK([_arr removeObject:anObject]);
}
- (void)removeObjectIdenticalTo:(id)anObject inRange:(NSRange)range {
VAP_LOCK([_arr removeObjectIdenticalTo:anObject inRange:range]);
}
- (void)removeObjectIdenticalTo:(id)anObject {
VAP_LOCK([_arr removeObjectIdenticalTo:anObject]);
}
- (void)removeObjectsInArray:(NSArray *)otherArray {
VAP_LOCK([_arr removeObjectsInArray:otherArray]);
}
- (void)removeObjectsInRange:(NSRange)range {
VAP_LOCK([_arr removeObjectsInRange:range]);
}
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray range:(NSRange)otherRange {
VAP_LOCK([_arr replaceObjectsInRange:range withObjectsFromArray:otherArray range:otherRange]);
}
- (void)replaceObjectsInRange:(NSRange)range withObjectsFromArray:(NSArray *)otherArray {
VAP_LOCK([_arr replaceObjectsInRange:range withObjectsFromArray:otherArray]);
}
- (void)setArray:(NSArray *)otherArray {
VAP_LOCK([_arr setArray:otherArray]);
}
- (void)sortUsingFunction:(__attribute__((noescape)) NSInteger (*)(id, id, void *))compare context:(void *)context {
VAP_LOCK([_arr sortUsingFunction:compare context:context]);
}
- (void)sortUsingSelector:(SEL)comparator {
VAP_LOCK([_arr sortUsingSelector:comparator]);
}
- (void)insertObjects:(NSArray *)objects atIndexes:(NSIndexSet *)indexes {
VAP_LOCK([_arr insertObjects:objects atIndexes:indexes]);
}
- (void)removeObjectsAtIndexes:(NSIndexSet *)indexes {
VAP_LOCK([_arr removeObjectsAtIndexes:indexes]);
}
- (void)replaceObjectsAtIndexes:(NSIndexSet *)indexes withObjects:(NSArray *)objects {
VAP_LOCK([_arr replaceObjectsAtIndexes:indexes withObjects:objects]);
}
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx {
VAP_LOCK([_arr setObject:obj atIndexedSubscript:idx]);
}
- (void)sortUsingComparator:(__attribute__((noescape)) NSComparator)cmptr {
VAP_LOCK([_arr sortUsingComparator:cmptr]);
}
- (void)sortWithOptions:(NSSortOptions)opts usingComparator:(__attribute__((noescape)) NSComparator)cmptr {
VAP_LOCK([_arr sortWithOptions:opts usingComparator:cmptr]);
}
- (BOOL)isEqualToArray:(NSArray *)otherArray {
if (otherArray == self) return YES;
if ([otherArray isKindOfClass:QGVAPSafeMutableArray.class]) {
QGVAPSafeMutableArray *other = (id)otherArray;
BOOL isEqual;
[_lock lock];
[other->_lock lock];
isEqual = [_arr isEqualToArray:other->_arr];
[other->_lock unlock];
[_lock unlock];
return isEqual;
}
return NO;
}
#pragma mark - protocol
- (id)copyWithZone:(NSZone *)zone {
return [self mutableCopyWithZone:zone];
}
- (id)mutableCopyWithZone:(NSZone *)zone {
VAP_LOCK(id copiedArr = [[self.class allocWithZone:zone] initWithArray:_arr]);
return copiedArr;
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id __unsafe_unretained[])stackbuf
count:(NSUInteger)len {
VAP_LOCK(NSUInteger count = [_arr countByEnumeratingWithState:state objects:stackbuf count:len]);
return count;
}
- (BOOL)isEqual:(id)object {
if (object == self) return YES;
if ([object isKindOfClass:[QGVAPSafeMutableArray class]]) {
QGVAPSafeMutableArray *other = object;
BOOL isEqual;
[_lock lock];
[other->_lock lock];
isEqual = [_arr isEqual:other->_arr];
[other->_lock unlock];
[_lock unlock];
return isEqual;
}
return NO;
}
- (NSUInteger)hash {
VAP_LOCK(NSUInteger hash = [_arr hash]);
return hash;
}
@end
@@ -0,0 +1,27 @@
// QGVAPSafeMutableDictionary.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <Foundation/Foundation.h>
/**
This class inherits from NSMutableDictionary, make it thread safe and allow Recursive lock.
@discussion access performance would lower than NSMutableDictionary, or using semaphore but equal to @sychronized.
@warning Fast enumerate and enumerator are not thread safe
*/
@interface QGVAPSafeMutableDictionary : NSMutableDictionary
@end
@@ -0,0 +1,237 @@
// QGVAPSafeMutableDictionary.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "QGVAPSafeMutableDictionary.h"
#define VAP_INIT(...) self = super.init; \
if (!self) return nil; \
__VA_ARGS__; \
if (!_dic) return nil; \
_lock = [[NSRecursiveLock alloc] init]; \
return self;
#define VAP_LOCK(...) [_lock lock]; \
__VA_ARGS__; \
[_lock unlock];
@interface QGVAPSafeMutableDictionary(){
NSMutableDictionary *_dic;
NSRecursiveLock *_lock;
}
@end
@implementation QGVAPSafeMutableDictionary
#pragma mark - init
- (instancetype)init {
VAP_INIT(_dic = [[NSMutableDictionary alloc] init]);
}
- (instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys {
VAP_INIT(_dic = [[NSMutableDictionary alloc] initWithObjects:objects forKeys:keys]);
}
- (instancetype)initWithCapacity:(NSUInteger)capacity {
VAP_INIT(_dic = [[NSMutableDictionary alloc] initWithCapacity:capacity]);
}
- (instancetype)initWithObjects:(const id[])objects forKeys:(const id <NSCopying>[])keys count:(NSUInteger)cnt {
VAP_INIT(_dic = [[NSMutableDictionary alloc] initWithObjects:objects forKeys:keys count:cnt]);
}
- (instancetype)initWithDictionary:(NSDictionary *)otherDictionary {
VAP_INIT(_dic = [[NSMutableDictionary alloc] initWithDictionary:otherDictionary]);
}
- (instancetype)initWithDictionary:(NSDictionary *)otherDictionary copyItems:(BOOL)flag {
VAP_INIT(_dic = [[NSMutableDictionary alloc] initWithDictionary:otherDictionary copyItems:flag]);
}
#pragma mark - method
- (NSUInteger)count {
VAP_LOCK(NSUInteger c = _dic.count); return c;
}
- (id)objectForKey:(id)aKey {
VAP_LOCK(id o = [_dic objectForKey:aKey]); return o;
}
- (NSEnumerator *)keyEnumerator {
VAP_LOCK(NSEnumerator * e = [_dic keyEnumerator]); return e;
}
- (NSArray *)allKeys {
VAP_LOCK(NSArray * a = [_dic allKeys]); return a;
}
- (NSArray *)allKeysForObject:(id)anObject {
VAP_LOCK(NSArray * a = [_dic allKeysForObject:anObject]); return a;
}
- (NSArray *)allValues {
VAP_LOCK(NSArray * a = [_dic allValues]); return a;
}
- (NSString *)description {
VAP_LOCK(NSString * d = [_dic description]); return d;
}
- (NSString *)descriptionInStringsFileFormat {
VAP_LOCK(NSString * d = [_dic descriptionInStringsFileFormat]); return d;
}
- (NSString *)descriptionWithLocale:(id)locale {
VAP_LOCK(NSString * d = [_dic descriptionWithLocale:locale]); return d;
}
- (NSString *)descriptionWithLocale:(id)locale indent:(NSUInteger)level {
VAP_LOCK(NSString * d = [_dic descriptionWithLocale:locale indent:level]); return d;
}
- (BOOL)isEqualToDictionary:(NSDictionary *)otherDictionary {
if (otherDictionary == self) return YES;
if ([otherDictionary isKindOfClass:QGVAPSafeMutableDictionary.class]) {
QGVAPSafeMutableDictionary *other = (id)otherDictionary;
BOOL isEqual;
[_lock lock];
[other->_lock lock];
isEqual = [_dic isEqual:other->_dic];
[other->_lock unlock];
[_lock unlock];
return isEqual;
}
return NO;
}
- (NSEnumerator *)objectEnumerator {
VAP_LOCK(NSEnumerator * e = [_dic objectEnumerator]); return e;
}
- (NSArray *)objectsForKeys:(NSArray *)keys notFoundMarker:(id)marker {
VAP_LOCK(NSArray * a = [_dic objectsForKeys:keys notFoundMarker:marker]); return a;
}
- (NSArray *)keysSortedByValueUsingSelector:(SEL)comparator {
VAP_LOCK(NSArray * a = [_dic keysSortedByValueUsingSelector:comparator]); return a;
}
- (void)getObjects:(id __unsafe_unretained[])objects andKeys:(id __unsafe_unretained[])keys {
VAP_LOCK([_dic getObjects:objects andKeys:keys]);
}
- (id)objectForKeyedSubscript:(id)key {
VAP_LOCK(id o = [_dic objectForKeyedSubscript:key]); return o;
}
- (void)enumerateKeysAndObjectsUsingBlock:(__attribute__((noescape)) void (^)(id key, id obj, BOOL *stop))block {
VAP_LOCK([_dic enumerateKeysAndObjectsUsingBlock:block]);
}
- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(__attribute__((noescape)) void (^)(id key, id obj, BOOL *stop))block {
VAP_LOCK([_dic enumerateKeysAndObjectsWithOptions:opts usingBlock:block]);
}
- (NSArray *)keysSortedByValueUsingComparator:(__attribute__((noescape)) NSComparator)cmptr {
VAP_LOCK(NSArray * a = [_dic keysSortedByValueUsingComparator:cmptr]); return a;
}
- (NSArray *)keysSortedByValueWithOptions:(NSSortOptions)opts usingComparator:(__attribute__((noescape)) NSComparator)cmptr {
VAP_LOCK(NSArray * a = [_dic keysSortedByValueWithOptions:opts usingComparator:cmptr]); return a;
}
- (NSSet *)keysOfEntriesPassingTest:(__attribute__((noescape)) BOOL (^)(id key, id obj, BOOL *stop))predicate {
VAP_LOCK(NSSet * a = [_dic keysOfEntriesPassingTest:predicate]); return a;
}
- (NSSet *)keysOfEntriesWithOptions:(NSEnumerationOptions)opts passingTest:(__attribute__((noescape)) BOOL (^)(id key, id obj, BOOL *stop))predicate {
VAP_LOCK(NSSet * a = [_dic keysOfEntriesWithOptions:opts passingTest:predicate]); return a;
}
#pragma mark - mutable
- (void)removeObjectForKey:(id)aKey {
VAP_LOCK([_dic removeObjectForKey:aKey]);
}
- (void)setObject:(id)anObject forKey:(id <NSCopying> )aKey {
VAP_LOCK([_dic setObject:anObject forKey:aKey]);
}
- (void)addEntriesFromDictionary:(NSDictionary *)otherDictionary {
VAP_LOCK([_dic addEntriesFromDictionary:otherDictionary]);
}
- (void)removeAllObjects {
VAP_LOCK([_dic removeAllObjects]);
}
- (void)removeObjectsForKeys:(NSArray *)keyArray {
VAP_LOCK([_dic removeObjectsForKeys:keyArray]);
}
- (void)setDictionary:(NSDictionary *)otherDictionary {
VAP_LOCK([_dic setDictionary:otherDictionary]);
}
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying> )key {
VAP_LOCK([_dic setObject:obj forKeyedSubscript:key]);
}
#pragma mark - protocol
- (id)copyWithZone:(NSZone *)zone {
return [self mutableCopyWithZone:zone];
}
- (id)mutableCopyWithZone:(NSZone *)zone {
VAP_LOCK(id copiedDictionary = [[self.class allocWithZone:zone] initWithDictionary:_dic]);
return copiedDictionary;
}
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state
objects:(id __unsafe_unretained[])stackbuf
count:(NSUInteger)len {
VAP_LOCK(NSUInteger count = [_dic countByEnumeratingWithState:state objects:stackbuf count:len]);
return count;
}
- (BOOL)isEqual:(id)object {
if (object == self) return YES;
if ([object isKindOfClass:QGVAPSafeMutableDictionary.class]) {
QGVAPSafeMutableDictionary *other = object;
BOOL isEqual;
[_lock lock];
[other->_lock lock];
isEqual = [_dic isEqual:other->_dic];
[other->_lock unlock];
[_lock unlock];
return isEqual;
}
return NO;
}
- (NSUInteger)hash {
VAP_LOCK(NSUInteger hash = [_dic hash]);
return hash;
}
@end
@@ -0,0 +1,24 @@
// QGVAPWeakProxy.h
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 <Foundation/Foundation.h>
@interface QGVAPWeakProxy : NSObject
- (instancetype)initWithTarget:(id)target;
+ (instancetype)proxyWithTarget:(id)target;
@end
@@ -0,0 +1,52 @@
// QGVAPWeakProxy.m
// Tencent is pleased to support the open source community by making vap available.
//
// Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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 "QGVAPWeakProxy.h"
@implementation QGVAPWeakProxy {
__weak id _target;
}
- (instancetype)initWithTarget:(id)target {
if (self = [super init]) {
_target = target;
}
return self;
}
+ (instancetype)proxyWithTarget:(id)target {
return [[QGVAPWeakProxy alloc] initWithTarget:target];
}
// 1. 快速消息转发
- (id)forwardingTargetForSelector:(SEL)aSelector {
return _target;
}
// 2. 如果<1>返回nil,到标准消息转发处理,如果不处理为Crashunrecognized selector. 这里我们直接返回空指针地址.
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [NSObject instanceMethodSignatureForSelector:@selector(init)];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
void *null = NULL;
[anInvocation setReturnValue:&null];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
return [_target respondsToSelector:aSelector];
}
@end