MLSOAppDelegate icon indicating copy to clipboard operation
MLSOAppDelegate copied to clipboard

大佬好,可以加个优先级参数吗,排序是很重要的 https://github.com/youzan/Bifrost 这个好像可以

Open ieliwb opened this issue 4 years ago • 3 comments

https://github.com/youzan/Bifrost ,可以加上吗,谢谢

ieliwb avatar Sep 17 '21 10:09 ieliwb

` #import <Foundation/Foundation.h> #import <UIKit/UIKit.h>

#define HH_EXPORT_SERVICE(name, sort) \

  • (void)load {[[HHAppServiceManager sharedManager] registerService:[self new]];} \
  • (NSString *)serviceName { return @#name; } \
  • (NSNumber *)priority { return @(sort); }

NS_ASSUME_NONNULL_BEGIN

@protocol HHAppService <UIApplicationDelegate>

@required

  • (NSString *)serviceName;
  • (NSNumber *)priority; @end

@interface HHAppServiceManager : NSObject

  • (instancetype)sharedManager;
  • (void)registerService:(id<HHAppService>)service;

  • (BOOL)proxyCanResponseToSelector:(SEL)aSelector;

  • (void)proxyForwardInvocation:(NSInvocation *)anInvocation;

@end

NS_ASSUME_NONNULL_END `

ieliwb avatar Sep 18 '21 10:09 ieliwb

` #import "HHAppServiceManager.h" #import <objc/runtime.h> #import <objc/message.h>

@interface HHAppServiceManager () @property (nonatomic, strong) Class<UIApplicationDelegate> appDelegateClass; @property (nonatomic, strong) NSMutableDictionary<NSString*, id<HHAppService>> servicesMap; @property (nonatomic, strong) NSMutableDictionary<NSNumber, NSString*> *servicesSort; @end

// 由子类实现服务代理方法,父类负责把这些实现添加到 ApplicationDelegate 中 // 这些都需要在 ApplicationDelegate 实例创建之前执行 @implementation HHAppServiceManager

  • (instancetype)sharedManager { static HHAppServiceManager *_sharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _sharedManager = [HHAppServiceManager new]; });

    return _sharedManager; }

  • (instancetype)init { if (self = [super init]) { self.servicesMap = [NSMutableDictionary dictionary]; self.servicesSort = [NSMutableDictionary dictionary]; } return self; }

  • (void)registerService:(id<HHAppService>)service { if (!service) { return; } id<HHAppService> pre = self.servicesMap[[service serviceName]]; if (pre) { if ([service isKindOfClass:[pre class]]) { self.servicesMap[[service serviceName]] = service; self.servicesSort[[service priority]] = [service serviceName]; } else { NSAssert([pre isKindOfClass:[service class]], @"Tried to register both %@ and %@ as the handler of %@ service.
    Cannot determine the right class to use because neither inherits from the other.", [pre class], [service class], [service serviceName]); } } else { self.servicesMap[[service serviceName]] = service; self.servicesSort[[service priority]] = [service serviceName]; } }

  • (NSArray *)sortKeysByIntValue:(NSDictionary *)dictionary { NSArray *sortedKeys = [dictionary keysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) { int v1 = [obj1 intValue]; int v2 = [obj2 intValue]; if (v1 < v2) return NSOrderedAscending; else if (v1 > v2) return NSOrderedDescending; else return NSOrderedSame; }]; return sortedKeys; }

#pragma mark - #pragma mark Proxy

  • (BOOL)proxyCanResponseToSelector:(SEL)aSelector { __block IMP imp = NULL;

    NSArray *sortedKeys = [self sortKeysByIntValue:self.servicesSort]; [sortedKeys enumerateObjectsUsingBlock:^(id _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) { id<HHAppService> obj = self.servicesMap[self.servicesSort[key]]; if ([obj respondsToSelector:aSelector]) { imp = [(id)obj methodForSelector:aSelector]; NSMethodSignature *signature = [(id)obj methodSignatureForSelector:aSelector]; if (signature.methodReturnLength > 0 && strcmp(signature.methodReturnType, @encode(BOOL)) != 0) { imp = NULL; } *stop = YES; } }]; return imp != NULL && imp != _objc_msgForward; }

  • (NSString *)objcTypesFromSignature:(NSMethodSignature *)signature { NSMutableString *types = [NSMutableString stringWithFormat:@"%s", signature.methodReturnType?:"v"]; for (NSUInteger i = 0; i < signature.numberOfArguments; i ++) { [types appendFormat:@"%s", [signature getArgumentTypeAtIndex:i]]; } return [types copy]; }

  • (void)proxyForwardInvocation:(NSInvocation *)anInvocation {

    NSMethodSignature *signature = anInvocation.methodSignature; NSUInteger argCount = signature.numberOfArguments; __block BOOL returnValue = NO; NSUInteger returnLength = signature.methodReturnLength; void * returnValueBytes = NULL; if (returnLength > 0) { returnValueBytes = alloca(returnLength); }

    NSArray *sortedKeys = [self sortKeysByIntValue:self.servicesSort]; [sortedKeys enumerateObjectsUsingBlock:^(id _Nonnull key, NSUInteger idx, BOOL * _Nonnull stop) { id<HHAppService> obj = self.servicesMap[self.servicesSort[key]];

      if ( ! [obj respondsToSelector:anInvocation.selector]) {
          return;
      }
    
      // check the signature
      NSAssert([[self objcTypesFromSignature:signature] isEqualToString:[self objcTypesFromSignature:[(id)obj methodSignatureForSelector:anInvocation.selector]]],
               @"Method signature for selector (%@) on (%@ - `%@`) is invalid. \
               Please check the return value type and arguments type.",
               NSStringFromSelector(anInvocation.selector), obj.serviceName, obj);
    
      // copy the invokation
      NSInvocation *invok = [NSInvocation invocationWithMethodSignature:signature];
      invok.selector = anInvocation.selector;
      // copy arguments
      for (NSUInteger i = 0; i < argCount; i ++) {
          const char * argType = [signature getArgumentTypeAtIndex:i];
          NSUInteger argSize = 0;
          NSGetSizeAndAlignment(argType, &argSize, NULL);
    
          void * argValue = alloca(argSize);
          [anInvocation getArgument:&argValue atIndex:i];
          [invok setArgument:&argValue atIndex:i];
      }
      // reset the target
      invok.target = obj;
      // invoke
      [invok invoke];
    
      // get the return value
      if (returnValueBytes) {
          [invok getReturnValue:returnValueBytes];
          returnValue = returnValue || *((BOOL *)returnValueBytes);
      }
    

    }];

    // set return value if (returnValueBytes) { [anInvocation setReturnValue:returnValueBytes]; } }

@end

`

ieliwb avatar Sep 18 '21 10:09 ieliwb

楼主代码很棒,我稍微改了一下,支持优先级priority,供大家参考

ieliwb avatar Sep 18 '21 10:09 ieliwb