566 lines
19 KiB
Objective-C
566 lines
19 KiB
Objective-C
|
|
// Created by Tencent on 2023/06/09.
|
|
// Copyright © 2023 Tencent. All rights reserved.
|
|
#import "TUICore.h"
|
|
|
|
#import <objc/runtime.h>
|
|
|
|
#import "TUIDefine.h"
|
|
#import "TUIThemeManager.h"
|
|
#import "TUIWeakProxy.h"
|
|
|
|
@implementation TUICore
|
|
|
|
+ (void)initialize {
|
|
TUIRegisterThemeResourcePath(TUICoreThemePath, TUIThemeModuleCore);
|
|
TUIRegisterThemeResourcePath(TUIBundlePath(@"TUICoreTheme_Minimalist", TUICoreBundle_Key_Class), TUIThemeModuleCore_Minimalist);
|
|
}
|
|
|
|
+ (void)registerService:(NSString *)serviceName object:(id<TUIServiceProtocol>)object {
|
|
[TUIServiceManager.shareInstance registerService:serviceName service:object];
|
|
}
|
|
|
|
+ (void)unregisterService:(NSString *)serviceName {
|
|
[TUIServiceManager.shareInstance unregisterService:serviceName];
|
|
}
|
|
|
|
+ (id<TUIServiceProtocol>)getService:(NSString *)serviceName {
|
|
return [TUIServiceManager.shareInstance getService:serviceName];
|
|
}
|
|
|
|
+ (id)callService:(NSString *)serviceName method:(NSString *)method param:(nullable NSDictionary *)param {
|
|
return [TUIServiceManager.shareInstance callService:serviceName method:method param:param resultCallback:nil];
|
|
}
|
|
|
|
+ (id)callService:(NSString *)serviceName
|
|
method:(NSString *)method
|
|
param:(nullable NSDictionary *)param
|
|
resultCallback:(nullable TUICallServiceResultCallback)resultCallback {
|
|
return [TUIServiceManager.shareInstance callService:serviceName method:method param:param resultCallback:resultCallback];
|
|
}
|
|
|
|
+ (void)registerEvent:(NSString *)key subKey:(NSString *)subKey object:(id<TUINotificationProtocol>)object {
|
|
[TUIEventManager.shareInstance registerEvent:key subKey:subKey object:object];
|
|
}
|
|
|
|
+ (void)unRegisterEventByObject:(id<TUINotificationProtocol>)object {
|
|
[TUIEventManager.shareInstance unRegisterEvent:object];
|
|
}
|
|
+ (void)unRegisterEvent:(nullable NSString *)key subKey:(nullable NSString *)subKey object:(nullable id<TUINotificationProtocol>)object {
|
|
[TUIEventManager.shareInstance unRegisterEvent:key subKey:subKey object:object];
|
|
}
|
|
|
|
+ (void)notifyEvent:(NSString *)key subKey:(NSString *)subKey object:(nullable id)anObject param:(nullable NSDictionary *)param {
|
|
[TUIEventManager.shareInstance notifyEvent:key subKey:subKey object:anObject param:param];
|
|
}
|
|
|
|
+ (void)registerExtension:(NSString *)extensionID object:(id<TUIExtensionProtocol>)object {
|
|
[TUIExtensionManager.shareInstance registerExtension:extensionID extension:object];
|
|
}
|
|
|
|
+ (void)unRegisterExtension:(NSString *)extensionID object:(id<TUIExtensionProtocol>)object {
|
|
[TUIExtensionManager.shareInstance unRegisterExtension:extensionID extension:object];
|
|
}
|
|
|
|
+ (NSDictionary *)getExtensionInfo:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
|
return [TUIExtensionManager.shareInstance getExtensionInfo:extensionID param:param];
|
|
}
|
|
|
|
+ (NSArray<TUIExtensionInfo *> *)getExtensionList:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
|
return [TUIExtensionManager.shareInstance getExtensionList:extensionID param:param];
|
|
}
|
|
|
|
+ (BOOL)raiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param {
|
|
return [TUIExtensionManager.shareInstance raiseExtension:extensionID parentView:parentView param:param];
|
|
}
|
|
|
|
+ (void)registerObjectFactory:(NSString *)factoryName objectFactory:(id<TUIObjectProtocol>)objectFactory {
|
|
[TUIObjectFactoryManager.shareInstance registerObjectFactory:factoryName objectFactory:objectFactory];
|
|
}
|
|
|
|
+ (void)unRegisterObjectFactory:(NSString *)factoryName {
|
|
[TUIObjectFactoryManager.shareInstance unRegisterObjectFactory:factoryName];
|
|
}
|
|
|
|
+ (id)createObject:(NSString *)factoryName key:(NSString *)key param:(NSDictionary *)param {
|
|
return [TUIObjectFactoryManager.shareInstance createObject:factoryName method:key param:param];
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - TUIRoute
|
|
|
|
static const void *navigateValueCallback = @"navigateValueCallback";
|
|
|
|
@implementation NSObject (TUIRoute)
|
|
|
|
- (void)setNavigateValueCallback:(TUIValueResultCallback)callback {
|
|
objc_setAssociatedObject(self, navigateValueCallback, callback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
|
}
|
|
|
|
- (TUIValueResultCallback)navigateValueCallback {
|
|
return objc_getAssociatedObject(self, navigateValueCallback);
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation UIViewController (TUIRoute)
|
|
|
|
- (void)pushViewController:(NSString *)viewControllerKey param:(nullable NSDictionary *)param forResult:(nullable TUIValueResultCallback)callback {
|
|
NSAssert([self isKindOfClass:UINavigationController.class], @"self must be a navigation controller");
|
|
UIViewController *vc = [TUIObjectFactoryManager.shareInstance createObject:viewControllerKey param:param];
|
|
if ([vc isKindOfClass:UIViewController.class]) {
|
|
vc.navigateValueCallback = callback;
|
|
[(UINavigationController *)self pushViewController:vc animated:YES];
|
|
} else {
|
|
NSAssert(false, @"viewControllerKey not exists or invalid");
|
|
}
|
|
}
|
|
|
|
- (void)presentViewController:(NSString *)viewControllerKey param:(nullable NSDictionary *)param forResult:(nullable TUIValueResultCallback)callback {
|
|
[self presentViewController:viewControllerKey param:param embbedIn:nil forResult:callback];
|
|
}
|
|
|
|
- (void)presentViewController:(NSString *)viewControllerKey
|
|
param:(nullable NSDictionary *)param
|
|
embbedIn:(nullable UINavigationController *)navigationVC
|
|
forResult:(nullable TUIValueResultCallback)callback {
|
|
UIViewController *vc = [TUIObjectFactoryManager.shareInstance createObject:viewControllerKey param:param];
|
|
if ([vc isKindOfClass:UIViewController.class]) {
|
|
vc.navigateValueCallback = callback;
|
|
if (navigationVC) {
|
|
if ([navigationVC isKindOfClass:UINavigationController.class]) {
|
|
NSMutableArray *arrayM = [NSMutableArray array];
|
|
if (navigationVC.viewControllers.count > 0) {
|
|
[arrayM addObjectsFromArray:navigationVC.viewControllers];
|
|
}
|
|
[arrayM addObject:vc];
|
|
navigationVC.viewControllers = [NSArray arrayWithArray:arrayM];
|
|
[self presentViewController:navigationVC animated:YES completion:nil];
|
|
} else {
|
|
NSAssert(false, @"navigationVC must be a navigation controller");
|
|
}
|
|
} else {
|
|
[self presentViewController:vc animated:YES completion:nil];
|
|
}
|
|
} else {
|
|
NSAssert(false, @"viewControllerKey not exists or invalid");
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - TUIService
|
|
|
|
@interface TUIServiceManager ()
|
|
|
|
@property(nonatomic, strong) NSMapTable<NSString *, id<TUIServiceProtocol>> *serviceMap;
|
|
|
|
@end
|
|
|
|
@implementation TUIServiceManager
|
|
|
|
+ (instancetype)shareInstance {
|
|
static id instance = nil;
|
|
if (instance == nil) {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
instance = [[self alloc] init];
|
|
});
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
- (void)registerService:(NSString *)serviceName service:(id<TUIServiceProtocol>)service {
|
|
NSAssert(serviceName.length > 0, @"invalid service name");
|
|
NSAssert(service != nil, @"invalid service");
|
|
|
|
if (serviceName && service) {
|
|
@synchronized(self.serviceMap) {
|
|
[self.serviceMap setObject:service forKey:serviceName];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)unregisterService:(NSString *)serviceName {
|
|
NSAssert(serviceName.length > 0, @"invalid service name");
|
|
|
|
if (serviceName) {
|
|
@synchronized(self.serviceMap) {
|
|
[self.serviceMap removeObjectForKey:serviceName];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (nullable id<TUIServiceProtocol>)getService:(NSString *)serviceName {
|
|
id<TUIServiceProtocol> service = nil;
|
|
@synchronized(self.serviceMap) {
|
|
service = [self.serviceMap objectForKey:serviceName];
|
|
}
|
|
return service;
|
|
}
|
|
|
|
- (nullable id)callService:(NSString *)serviceName
|
|
method:(NSString *)method
|
|
param:(nullable NSDictionary *)param
|
|
resultCallback:(nullable TUICallServiceResultCallback)resultCallback {
|
|
NSAssert(serviceName.length > 0, @"invalid service name");
|
|
NSAssert(method.length > 0, @"invalid method");
|
|
|
|
id<TUIServiceProtocol> service = [self getService:serviceName];
|
|
id result = nil;
|
|
if (resultCallback) {
|
|
if (service && [service respondsToSelector:@selector(onCall:param:resultCallback:)]) {
|
|
result = [service onCall:method param:param resultCallback:resultCallback];
|
|
}
|
|
} else {
|
|
if (service && [service respondsToSelector:@selector(onCall:param:)]) {
|
|
result = [service onCall:method param:param];
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
- (NSMapTable<NSString *, id<TUIServiceProtocol>> *)serviceMap {
|
|
if (_serviceMap == nil) {
|
|
_serviceMap = [NSMapTable strongToWeakObjectsMapTable];
|
|
}
|
|
return _serviceMap;
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - TUIEvent
|
|
|
|
@interface TUIEventManager ()
|
|
|
|
@property(nonatomic, strong) NSMutableArray<NSDictionary *> *eventList;
|
|
|
|
@end
|
|
|
|
@implementation TUIEventManager
|
|
|
|
+ (instancetype)shareInstance {
|
|
static id instance = nil;
|
|
if (instance == nil) {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
instance = [[self alloc] init];
|
|
});
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
- (void)registerEvent:(NSString *)key subKey:(NSString *)subKey object:(id<TUINotificationProtocol>)object {
|
|
NSAssert(key.length > 0, @"invalid key");
|
|
NSAssert(object != nil, @"invalid object");
|
|
|
|
if (subKey.length == 0) {
|
|
subKey = @"";
|
|
}
|
|
|
|
if (key && subKey && object) {
|
|
NSDictionary *event = @{@"key" : [key copy], @"subKey" : [subKey copy], @"object" : [TUIWeakProxy proxyWithTarget:object]};
|
|
|
|
@synchronized(self.eventList) {
|
|
[self.eventList addObject:event];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)unRegisterEvent:(id<TUINotificationProtocol>)object {
|
|
[self unRegisterEvent:nil subKey:nil object:object];
|
|
}
|
|
|
|
- (void)unRegisterEvent:(nullable NSString *)key subKey:(nullable NSString *)subKey object:(nullable id<TUINotificationProtocol>)object {
|
|
@synchronized(self.eventList) {
|
|
NSMutableArray *removeEventList = [NSMutableArray array];
|
|
for (NSDictionary *event in self.eventList) {
|
|
NSString *pkey = [event objectForKey:@"key"];
|
|
NSString *pSubKey = [event objectForKey:@"subKey"];
|
|
id pObject = [event objectForKey:@"object"];
|
|
|
|
if (pObject == nil || [(TUIWeakProxy *)pObject target] == nil) {
|
|
[removeEventList addObject:event];
|
|
}
|
|
if (key == nil && subKey == nil && pObject == object) {
|
|
[removeEventList addObject:event];
|
|
} else if ([pkey isEqualToString:key] && subKey == nil && object == nil) {
|
|
[removeEventList addObject:event];
|
|
} else if ([pkey isEqualToString:key] && [subKey isEqualToString:pSubKey] && object == nil) {
|
|
[removeEventList addObject:event];
|
|
} else if ([pkey isEqualToString:key] && [subKey isEqualToString:pSubKey] && pObject == object) {
|
|
[removeEventList addObject:event];
|
|
}
|
|
}
|
|
[self.eventList removeObjectsInArray:removeEventList];
|
|
}
|
|
}
|
|
|
|
- (void)notifyEvent:(NSString *)key subKey:(NSString *)subKey object:(nullable id)object param:(nullable NSDictionary *)param {
|
|
NSAssert(key.length > 0, @"invalid key");
|
|
|
|
if (subKey.length == 0) {
|
|
subKey = @"";
|
|
}
|
|
|
|
@synchronized(self.eventList) {
|
|
for (NSDictionary *event in self.eventList) {
|
|
NSString *pkey = [event objectForKey:@"key"];
|
|
NSString *pSubKey = [event objectForKey:@"subKey"];
|
|
|
|
if ([pkey isEqualToString:key] && [pSubKey isEqualToString:subKey]) {
|
|
id<TUINotificationProtocol> pObject = [event objectForKey:@"object"];
|
|
if (pObject) {
|
|
[pObject onNotifyEvent:key subKey:subKey object:object param:param];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSMutableArray<NSDictionary *> *)eventList {
|
|
if (_eventList == nil) {
|
|
_eventList = [NSMutableArray array];
|
|
}
|
|
return _eventList;
|
|
}
|
|
|
|
@end
|
|
|
|
#pragma mark - TUIExtension
|
|
|
|
@implementation TUIExtensionInfo
|
|
|
|
@end
|
|
|
|
@interface TUIExtensionManager ()
|
|
|
|
@property(nonatomic, strong) NSMutableDictionary<NSString *, NSHashTable<id<TUIExtensionProtocol>> *> *extensionMap;
|
|
|
|
@end
|
|
|
|
@implementation TUIExtensionManager
|
|
|
|
+ (instancetype)shareInstance {
|
|
static id instance = nil;
|
|
if (instance == nil) {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
instance = [[self alloc] init];
|
|
});
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
- (void)registerExtension:(NSString *)extensionID extension:(id<TUIExtensionProtocol>)extension {
|
|
NSAssert(extensionID.length > 0, @"invalid extension id");
|
|
NSAssert(extension != nil, @"invalid extension");
|
|
|
|
if (extensionID && extension) {
|
|
@synchronized(self.extensionMap) {
|
|
NSHashTable *list = [self.extensionMap objectForKey:extensionID];
|
|
if (list == nil) {
|
|
list = [NSHashTable weakObjectsHashTable];
|
|
}
|
|
[list addObject:extension];
|
|
[self.extensionMap setObject:list forKey:extensionID];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)unRegisterExtension:(NSString *)extensionID extension:(id<TUIExtensionProtocol>)extension {
|
|
NSAssert(extensionID.length > 0, @"invalid extension id");
|
|
NSAssert(extension != nil, @"invalid extension");
|
|
|
|
if (extensionID && extension) {
|
|
@synchronized(self.extensionMap) {
|
|
NSHashTable *list = [self.extensionMap objectForKey:extensionID];
|
|
if (list == nil) {
|
|
list = [NSHashTable weakObjectsHashTable];
|
|
}
|
|
[list removeObject:extension];
|
|
[self.extensionMap setObject:list forKey:extensionID];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (NSArray<TUIExtensionInfo *> *)getExtensionList:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
|
NSAssert(extensionID.length > 0, @"invalid extension id");
|
|
|
|
NSHashTable *list = nil;
|
|
@synchronized(self.extensionMap) {
|
|
list = [self.extensionMap objectForKey:extensionID];
|
|
}
|
|
if (list == nil || list.count == 0) {
|
|
return @[];
|
|
}
|
|
|
|
// get
|
|
NSMutableArray *resultExtensionInfoList = [NSMutableArray array];
|
|
for (id<TUIExtensionProtocol> observer in list) {
|
|
if (observer && [observer respondsToSelector:@selector(onGetExtension:param:)]) {
|
|
NSArray<TUIExtensionInfo *> *infoList = [observer onGetExtension:extensionID param:param];
|
|
if (infoList) {
|
|
[resultExtensionInfoList addObjectsFromArray:infoList];
|
|
}
|
|
}
|
|
}
|
|
|
|
// sort
|
|
NSArray *result = [resultExtensionInfoList sortedArrayUsingComparator:^NSComparisonResult(TUIExtensionInfo *obj1, TUIExtensionInfo *obj2) {
|
|
if (obj1.weight > obj2.weight) {
|
|
return NSOrderedAscending;
|
|
} else {
|
|
return NSOrderedDescending;
|
|
}
|
|
}];
|
|
|
|
return result;
|
|
}
|
|
|
|
- (BOOL)raiseExtension:(NSString *)extensionID parentView:(UIView *)parentView param:(nullable NSDictionary *)param {
|
|
NSAssert(extensionID.length > 0, @"invalid extension id");
|
|
NSAssert(parentView != nil, @"invalid parent view");
|
|
|
|
NSHashTable *list = nil;
|
|
@synchronized(self.extensionMap) {
|
|
list = [self.extensionMap objectForKey:extensionID];
|
|
}
|
|
if (list == nil || list.count == 0) {
|
|
return NO;
|
|
}
|
|
|
|
BOOL isResponserExist = NO;
|
|
for (id<TUIExtensionProtocol> observer in list) {
|
|
if (observer && [observer respondsToSelector:@selector(onRaiseExtension:parentView:param:)]) {
|
|
isResponserExist = [observer onRaiseExtension:extensionID parentView:parentView param:param];
|
|
if (isResponserExist) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return isResponserExist;
|
|
}
|
|
|
|
- (NSDictionary *)getExtensionInfo:(NSString *)extensionID param:(nullable NSDictionary *)param {
|
|
NSAssert(extensionID.length > 0, @"invalid extension id");
|
|
|
|
NSHashTable *list = nil;
|
|
@synchronized(self.extensionMap) {
|
|
list = [self.extensionMap objectForKey:extensionID];
|
|
}
|
|
if (list == nil || list.count == 0) {
|
|
return nil;
|
|
}
|
|
|
|
for (id<TUIExtensionProtocol> observer in list) {
|
|
if (observer && [observer respondsToSelector:@selector(onGetExtensionInfo:param:)]) {
|
|
NSDictionary *info = [observer onGetExtensionInfo:extensionID param:param];
|
|
if (info) {
|
|
return info;
|
|
}
|
|
}
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
- (NSMutableDictionary<NSString *, NSHashTable<id<TUIExtensionProtocol>> *> *)extensionMap {
|
|
if (_extensionMap == nil) {
|
|
_extensionMap = [NSMutableDictionary dictionary];
|
|
}
|
|
return _extensionMap;
|
|
}
|
|
@end
|
|
|
|
#pragma mark - TUIObjectFactory
|
|
|
|
@interface TUIObjectFactoryManager ()
|
|
|
|
@property(nonatomic, strong) NSMapTable<NSString *, id<TUIObjectProtocol>> *objectFactoryMap;
|
|
|
|
@end
|
|
|
|
@implementation TUIObjectFactoryManager : NSObject
|
|
|
|
+ (instancetype)shareInstance {
|
|
static id instance = nil;
|
|
if (instance == nil) {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
instance = [[self alloc] init];
|
|
});
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
- (void)registerObjectFactory:(NSString *)factoryName objectFactory:(id<TUIObjectProtocol>)objectFactory {
|
|
NSAssert(factoryName.length > 0, @"invalid factory name");
|
|
NSAssert(objectFactory != nil, @"invalid object factory");
|
|
|
|
if (factoryName && objectFactory) {
|
|
@synchronized(self.objectFactoryMap) {
|
|
[self.objectFactoryMap setObject:objectFactory forKey:factoryName];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)unRegisterObjectFactory:(NSString *)factoryName {
|
|
NSAssert(factoryName.length > 0, @"invalid factory name");
|
|
|
|
if (factoryName) {
|
|
@synchronized(self.objectFactoryMap) {
|
|
[self.objectFactoryMap removeObjectForKey:factoryName];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (nullable id)createObject:(NSString *)factoryName method:(NSString *)method param:(nullable NSDictionary *)param {
|
|
NSAssert(factoryName.length > 0, @"invalid factory name");
|
|
NSAssert(method.length > 0, @"invalid method");
|
|
|
|
id<TUIObjectProtocol> factory = nil;
|
|
@synchronized(self.objectFactoryMap) {
|
|
factory = [self.objectFactoryMap objectForKey:factoryName];
|
|
}
|
|
|
|
if (factory && [factory respondsToSelector:@selector(onCreateObject:param:)]) {
|
|
return [factory onCreateObject:method param:param];
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (nullable id)createObject:(NSString *)method param:(NSDictionary *)param {
|
|
NSAssert(method.length > 0, @"invalid method");
|
|
|
|
NSArray<id<TUIObjectProtocol>> *list = nil;
|
|
@synchronized(self.objectFactoryMap) {
|
|
list = self.objectFactoryMap.objectEnumerator.allObjects;
|
|
}
|
|
if (list == nil || list.count == 0) {
|
|
return nil;
|
|
}
|
|
|
|
for (id<TUIObjectProtocol> factory in list) {
|
|
if (factory && [factory respondsToSelector:@selector(onCreateObject:param:)]) {
|
|
id obj = [factory onCreateObject:method param:param];
|
|
if (obj) {
|
|
return obj;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
- (NSMapTable<NSString *, id<TUIObjectProtocol>> *)objectFactoryMap {
|
|
if (_objectFactoryMap == nil) {
|
|
_objectFactoryMap = [NSMapTable strongToWeakObjectsMapTable];
|
|
}
|
|
return _objectFactoryMap;
|
|
}
|
|
|
|
@end
|