You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ac...@apache.org on 2018/04/26 12:39:55 UTC
[03/16] incubator-weex git commit: [WEEX-311] [iOS] use new
layoutEngin to replace yoga
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
new file mode 100644
index 0000000..c8c6e3f
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
@@ -0,0 +1,1158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "WXComponentManager.h"
+#import "WXComponent.h"
+#import "WXComponent_internal.h"
+#import "WXComponent+DataBinding.h"
+#import "WXComponentFactory.h"
+#import "WXDefine.h"
+#import "NSArray+Weex.h"
+#import "WXSDKInstance.h"
+#import "WXAssert.h"
+#import "WXUtility.h"
+#import "WXMonitor.h"
+#import "WXScrollerProtocol.h"
+#import "WXSDKManager.h"
+#import "WXSDKError.h"
+#import "WXInvocationConfig.h"
+#import "WXHandlerFactory.h"
+#import "WXValidateProtocol.h"
+#import "WXPrerenderManager.h"
+#import "WXTracingManager.h"
+#import "WXLayoutDefine.h"
+#import "WXSDKInstance_performance.h"
+#import "WXRootView.h"
+#import "WXComponent+Layout.h"
+
+
+
+static NSThread *WXComponentThread;
+
+#define WXAssertComponentExist(component) WXAssert(component, @"component not exists")
+
+
+@implementation WXComponentManager
+{
+ __weak WXSDKInstance *_weexInstance;
+ BOOL _isValid;
+
+ BOOL _stopRunning;
+ NSUInteger _noTaskTickCount;
+
+ // access only on component thread
+ NSMapTable<NSString *, WXComponent *> *_indexDict;
+ NSMutableArray<dispatch_block_t> *_uiTaskQueue;
+ NSMutableDictionary *_uiPrerenderTaskQueue;
+
+ WXComponent *_rootComponent;
+ NSMutableArray *_fixedComponents;
+//#ifndef USE_FLEX
+ css_node_t *_rootCSSNode;
+//#else
+ WeexCore::WXCoreLayoutNode* _rootFlexCSSNode;
+//#endif
+ CADisplayLink *_displayLink;
+}
+
++ (instancetype)sharedManager
+{
+ static id _sharedInstance = nil;
+ static dispatch_once_t oncePredicate;
+ dispatch_once(&oncePredicate, ^{
+ _sharedInstance = [[self alloc] init];
+ });
+ return _sharedInstance;
+}
+
+- (instancetype)initWithWeexInstance:(id)weexInstance
+{
+ if (self = [self init]) {
+ _weexInstance = weexInstance;
+
+ _indexDict = [NSMapTable strongToWeakObjectsMapTable];
+ _fixedComponents = [NSMutableArray wx_mutableArrayUsingWeakReferences];
+ _uiTaskQueue = [NSMutableArray array];
+ _isValid = YES;
+ [self _startDisplayLink];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ free_css_node(_rootCSSNode);
+ }
+
+//#else
+
+ if(_rootFlexCSSNode){
+ delete _rootFlexCSSNode;
+
+ // WeexCore::WXCoreLayoutNode::freeNodeTree(_rootFlexCSSNode);
+ _rootFlexCSSNode=nullptr;
+ }
+//#endif
+ [NSMutableArray wx_releaseArray:_fixedComponents];
+}
+
+#pragma mark Thread Management
+
++ (NSThread *)componentThread
+{
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ WXComponentThread = [[NSThread alloc] initWithTarget:[self sharedManager] selector:@selector(_runLoopThread) object:nil];
+ [WXComponentThread setName:WX_COMPONENT_THREAD_NAME];
+ if(WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
+ [WXComponentThread setQualityOfService:[[NSThread mainThread] qualityOfService]];
+ } else {
+ [WXComponentThread setThreadPriority:[[NSThread mainThread] threadPriority]];
+ }
+
+ [WXComponentThread start];
+ });
+
+ return WXComponentThread;
+}
+
+- (void)_runLoopThread
+{
+ [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
+
+ while (!_stopRunning) {
+ @autoreleasepool {
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+ }
+ }
+}
+
++ (void)_performBlockOnComponentThread:(void (^)(void))block
+{
+ if([NSThread currentThread] == [self componentThread]){
+ block();
+ } else {
+ [self performSelector:@selector(_performBlockOnComponentThread:)
+ onThread:WXComponentThread
+ withObject:[block copy]
+ waitUntilDone:NO];
+ }
+}
+
++ (void)_performBlockSyncOnComponentThread:(void (^)(void))block
+{
+ if([NSThread currentThread] == [self componentThread]){
+ block();
+ } else {
+ [self performSelector:@selector(_performBlockOnComponentThread:)
+ onThread:WXComponentThread
+ withObject:[block copy]
+ waitUntilDone:YES];
+ }
+}
+
+- (void)startComponentTasks
+{
+ [self _awakeDisplayLink];
+}
+
+- (void)rootViewFrameDidChange:(CGRect)frame
+{
+ WXAssertComponentThread();
+//#ifndef USE_FLEX
+
+ if (![WXComponent isUseFlex]) {
+ if (_rootCSSNode) {
+ [self _applyRootFrame:frame toRootCSSNode:_rootCSSNode];
+ if (!_rootComponent.styles[@"width"]) {
+ _rootComponent.cssNode->style.dimensions[CSS_WIDTH] = frame.size.width ?: CSS_UNDEFINED;
+ }
+ if (!_rootComponent.styles[@"height"]) {
+ _rootComponent.cssNode->style.dimensions[CSS_HEIGHT] = frame.size.height ?: CSS_UNDEFINED;
+ }
+ }
+ }
+//#else
+ else
+ {
+ if (_rootFlexCSSNode) {
+ [self _applyRootFrame:frame];
+ if (!_rootComponent.styles[@"width"]) {
+ _rootComponent.flexCssNode->setStyleWidth(frame.size.width ?:FlexUndefined,NO);
+ }
+ if (!_rootComponent.styles[@"height"]) {
+ _rootComponent.flexCssNode->setStyleHeight(frame.size.height ?:FlexUndefined);
+ }
+ }
+ }
+//#endif
+ [_rootComponent setNeedsLayout];
+ [self startComponentTasks];
+}
+
+//#ifndef USE_FLEX
+- (void)_applyRootFrame:(CGRect)rootFrame toRootCSSNode:(css_node_t *)rootCSSNode
+{
+ _rootCSSNode->style.position[CSS_LEFT] = self.weexInstance.frame.origin.x;
+ _rootCSSNode->style.position[CSS_TOP] = self.weexInstance.frame.origin.y;
+ // if no instance width/height, use layout width/height, as Android's wrap_content
+ _rootCSSNode->style.dimensions[CSS_WIDTH] = self.weexInstance.frame.size.width ?: CSS_UNDEFINED;
+ _rootCSSNode->style.dimensions[CSS_HEIGHT] = self.weexInstance.frame.size.height ?: CSS_UNDEFINED;
+}
+//#else
+- (void)_applyRootFrame:(CGRect)rootFrame{
+ _rootFlexCSSNode->setStylePosition(WeexCore::kPositionEdgeLeft, self.weexInstance.frame.origin.x);
+ _rootFlexCSSNode->setStylePosition(WeexCore::kPositionEdgeTop, self.weexInstance.frame.origin.y);
+ _rootFlexCSSNode->setStyleWidth(self.weexInstance.frame.size.width ?: FlexUndefined,NO);
+ _rootFlexCSSNode->setStyleHeight(self.weexInstance.frame.size.height ?: FlexUndefined);
+}
+//#endif
+
+- (void)_addUITask:(void (^)(void))block
+{
+ if(!_uiPrerenderTaskQueue){
+ _uiPrerenderTaskQueue = [NSMutableDictionary new];
+ }
+ if(self.weexInstance.needPrerender){
+ NSMutableArray<dispatch_block_t> *tasks = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+ if(!tasks){
+ tasks = [NSMutableArray new];
+ }
+ [tasks addObject:block];
+ [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+ }else{
+ [_uiTaskQueue addObject:block];
+ }
+}
+
+- (void)excutePrerenderUITask:(NSString *)url
+{
+ NSMutableArray *tasks = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+ for (id block in tasks) {
+ [_uiTaskQueue addObject:block];
+ }
+ tasks = [NSMutableArray new];
+ [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
+}
+
+#pragma mark Component Tree Building
+
+- (void)createRoot:(NSDictionary *)data
+{
+ WXAssertComponentThread();
+ WXAssertParam(data);
+
+ _rootComponent = [self _buildComponentForData:data supercomponent:nil];
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ [self _initRootCSSNode];
+ }
+//#else
+ else
+ {
+ [self _initRootFlexCssNode];
+ _rootFlexCSSNode->addChildAt(_rootComponent.flexCssNode, (uint32_t)[_fixedComponents count]);
+ }
+//#endif
+
+ NSArray *subcomponentsData = [data valueForKey:@"children"];
+ if (subcomponentsData) {
+ BOOL appendTree = [_rootComponent.attributes[@"append"] isEqualToString:@"tree"];
+ for(NSDictionary *subcomponentData in subcomponentsData){
+ [self _recursivelyAddComponent:subcomponentData toSupercomponent:_rootComponent atIndex:-1 appendingInTree:appendTree];
+ }
+ }
+
+ __weak typeof(self) weakSelf = self;
+ WX_MONITOR_INSTANCE_PERF_END(WXFirstScreenJSFExecuteTime, self.weexInstance);
+ [self _addUITask:^{
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingBegin functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
+ __strong typeof(self) strongSelf = weakSelf;
+ strongSelf.weexInstance.rootView.wx_component = strongSelf->_rootComponent;
+ [strongSelf.weexInstance.rootView addSubview:strongSelf->_rootComponent.view];
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingEnd functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
+ }];
+
+
+}
+
+//#ifndef USE_FLEX
+static bool rootNodeIsDirty(void *context)
+{
+ WXComponentManager *manager = (__bridge WXComponentManager *)(context);
+ return [manager->_rootComponent needsLayout];
+}
+
+static css_node_t * rootNodeGetChild(void *context, int i)
+{
+ WXComponentManager *manager = (__bridge WXComponentManager *)(context);
+ if (i == 0) {
+ return manager->_rootComponent.cssNode;
+ } else if(manager->_fixedComponents.count >= i) {
+ return ((WXComponent *)((manager->_fixedComponents)[i-1])).cssNode;
+ }
+
+ return NULL;
+}
+//#endif
+
+- (void)addComponent:(NSDictionary *)componentData toSupercomponent:(NSString *)superRef atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
+{
+ WXAssertComponentThread();
+ WXAssertParam(componentData);
+ WXAssertParam(superRef);
+
+ WXComponent *supercomponent = [_indexDict objectForKey:superRef];
+ WXAssertComponentExist(supercomponent);
+
+ if ([WXComponent isUseFlex] && !supercomponent) {
+ WXLogWarning(@"addComponent,superRef from js never exit ! check JS action, supRef:%@",superRef);
+ return;
+ }
+
+ [self _recursivelyAddComponent:componentData toSupercomponent:supercomponent atIndex:index appendingInTree:appendingInTree];
+}
+
+- (void)_recursivelyAddComponent:(NSDictionary *)componentData toSupercomponent:(WXComponent *)supercomponent atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
+{
+ WXComponent *component = [self _buildComponentForData:componentData supercomponent:supercomponent];
+ if (!supercomponent.subcomponents) {
+ index = 0;
+ } else {
+ index = (index == -1 ? supercomponent->_subcomponents.count : index);
+ }
+
+#ifdef DEBUG
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ WXLogDebug(@"flexLayout -> _recursivelyAddComponent : super:(%@,%@):[%f,%f] ,child:(%@,%@):[%f,%f],childClass:%@",
+ supercomponent.type,
+ supercomponent.ref,
+ supercomponent.cssNode->style.dimensions[CSS_WIDTH],
+ supercomponent.cssNode->style.dimensions[CSS_HEIGHT],
+ component.type,
+ component.ref,
+ component.cssNode->style.dimensions[CSS_WIDTH],
+ component.cssNode->style.dimensions[CSS_HEIGHT]
+ ,NSStringFromClass([component class])
+ );
+ }
+//#else
+ else
+ {
+ WXLogDebug(@"flexLayout -> _recursivelyAddComponent : super:(%@,%@):[%f,%f] ,child:(%@,%@):[%f,%f],childClass:%@",
+ supercomponent.type,
+ supercomponent.ref,
+ supercomponent.flexCssNode->getStyleWidth(),
+ supercomponent.flexCssNode->getStyleHeight(),
+ component.type,
+ component.ref,
+ component.flexCssNode->getStyleWidth(),
+ component.flexCssNode->getStyleHeight()
+ ,NSStringFromClass([component class])
+ );
+ }
+//#endif
+#endif //DEBUG
+
+
+ [supercomponent _insertSubcomponent:component atIndex:index];
+ // use _lazyCreateView to forbid component like cell's view creating
+ if(supercomponent && component && supercomponent->_lazyCreateView) {
+ component->_lazyCreateView = YES;
+ }
+
+ [self recordMaximumVirtualDom:component];
+
+ if (!component->_isTemplate) {
+ __weak typeof(self) weakSelf = self;
+ BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
+ [self _addUITask:^{
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+ [supercomponent insertSubview:component atIndex:index];
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+ [weakSelf onElementChange:isFSCreateFinish];
+ }];
+ }
+
+ NSArray *subcomponentsData = [componentData valueForKey:@"children"];
+
+ BOOL appendTree = !appendingInTree && [component.attributes[@"append"] isEqualToString:@"tree"];
+ // if ancestor is appending tree, child should not be laid out again even it is appending tree.
+ for(NSDictionary *subcomponentData in subcomponentsData){
+ [self _recursivelyAddComponent:subcomponentData toSupercomponent:component atIndex:-1 appendingInTree:appendTree || appendingInTree];
+ }
+
+ [component _didInserted];
+
+ if (appendTree) {
+ // If appending treeļ¼force layout in case of too much tasks piling up in syncQueue
+ [self _layoutAndSyncUI];
+ }
+}
+
+- (void)moveComponent:(NSString *)ref toSuper:(NSString *)superRef atIndex:(NSInteger)index
+{
+ WXAssertComponentThread();
+ WXAssertParam(ref);
+ WXAssertParam(superRef);
+
+ WXComponent *component = [_indexDict objectForKey:ref];
+ WXComponent *newSupercomponent = [_indexDict objectForKey:superRef];
+ WXAssertComponentExist(component);
+ WXAssertComponentExist(newSupercomponent);
+
+ if (component.supercomponent == newSupercomponent && [newSupercomponent.subcomponents indexOfObject:component] < index) {
+ // if the supercomponent moved to is the same as original supercomponent,
+ // unify it into the index after removing.
+ index--;
+ }
+
+ [component _moveToSupercomponent:newSupercomponent atIndex:index];
+ __weak typeof(self) weakSelf = self;
+ [self _addUITask:^{
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+ [component moveToSuperview:newSupercomponent atIndex:index];
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
+ }];
+}
+
+- (void)removeComponent:(NSString *)ref
+{
+ WXAssertComponentThread();
+ WXAssertParam(ref);
+
+ WXComponent *component = [_indexDict objectForKey:ref];
+ WXAssertComponentExist(component);
+
+ if ([WXComponent isUseFlex] && !component) {
+ WXLogWarning(@"removeComponent ref from js never exit ! check JS action, ref :%@",ref);
+ return;
+ }
+
+ [component _removeFromSupercomponent];
+
+ [_indexDict removeObjectForKey:ref];
+
+ __weak typeof(self) weakSelf = self;
+ BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
+ [self _addUITask:^{
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
+ if (component.supercomponent) {
+ [component.supercomponent willRemoveSubview:component];
+ }
+ [component removeFromSuperview];
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
+ [weakSelf onElementChange:isFSCreateFinish];
+ }];
+
+ [self _checkFixedSubcomponentToRemove:component];
+
+}
+
+- (void)onElementChange:(BOOL)isFSCreateFinish
+{
+ if (!isFSCreateFinish) {
+ return;
+ }
+
+ UIView *root = [self weexInstance].rootView;
+ BOOL hasEvent = TRUE;
+ if (root && [root isKindOfClass:[WXRootView class]]) {
+ WXRootView* wxRootView = (WXRootView *)root;
+ hasEvent = [wxRootView isHasEvent];
+ }
+ if (hasEvent) {
+ return;
+ }
+ double current = CACurrentMediaTime()*1000;
+
+ double diff = current - [self weexInstance].performance.jsCreateFinishTime;
+ if (diff > 8000) {
+ return;
+ }
+ [self weexInstance].performance.interactionTime = current - self.weexInstance.performance.renderTimeOrigin;
+}
+
+- (void)recordMaximumVirtualDom:(WXComponent*) component
+{
+ WXAssertComponentExist(component);
+ if(!component){
+ return;
+ }
+ int maxDeep =0;
+ while (component) {
+ maxDeep++;
+ component = component.supercomponent;
+ }
+ if(maxDeep > [self weexInstance].performance.maxVdomDeep)
+ {
+ [self weexInstance].performance.maxVdomDeep = maxDeep;
+ }
+
+}
+
+- (void)_checkFixedSubcomponentToRemove:(WXComponent *)component
+{
+ for (WXComponent *subcomponent in component.subcomponents) {
+ if (subcomponent->_positionType == WXPositionTypeFixed) {
+ [self _addUITask:^{
+ [subcomponent removeFromSuperview];
+ }];
+ }
+
+ [self _checkFixedSubcomponentToRemove:subcomponent];
+ }
+}
+
+- (WXComponent *)componentForRef:(NSString *)ref
+{
+ WXAssertComponentThread();
+
+ return [_indexDict objectForKey:ref];
+}
+
+- (WXComponent *)componentForRoot
+{
+ return _rootComponent;
+}
+
+- (NSUInteger)numberOfComponents
+{
+ WXAssertComponentThread();
+
+ return _indexDict.count;
+}
+
+- (WXComponent *)_buildComponentForData:(NSDictionary *)data supercomponent:(WXComponent *)supercomponent
+{
+ NSString *ref = data[@"ref"];
+ NSString *type = data[@"type"];
+ NSDictionary *styles = data[@"style"];
+ NSDictionary *attributes = data[@"attr"];
+ NSArray *events = data[@"event"];
+
+ if (self.weexInstance.needValidate) {
+ id<WXValidateProtocol> validateHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXValidateProtocol)];
+ if (validateHandler) {
+ WXComponentValidateResult* validateResult;
+ if ([validateHandler respondsToSelector:@selector(validateWithWXSDKInstance:component:supercomponent:)]) {
+ validateResult = [validateHandler validateWithWXSDKInstance:self.weexInstance component:type supercomponent:supercomponent];
+ }
+ if (validateResult==nil || !validateResult.isSuccess) {
+ type = validateResult.replacedComponent? validateResult.replacedComponent : @"div";
+ WXLogError(@"%@",[validateResult.error.userInfo objectForKey:@"errorMsg"]);
+ }
+ }
+ }
+
+ WXComponentConfig *config = [WXComponentFactory configWithComponentName:type];
+ BOOL isTemplate = [config.properties[@"isTemplate"] boolValue] || (supercomponent && supercomponent->_isTemplate);
+ NSDictionary *bindingStyles;
+ NSDictionary *bindingAttibutes;
+ NSDictionary *bindingEvents;
+ NSDictionary *bindingProps;
+ if (isTemplate) {
+ bindingProps = [self _extractBindingProps:&attributes];
+ bindingStyles = [self _extractBindings:&styles];
+ bindingAttibutes = [self _extractBindings:&attributes];
+ bindingEvents = [self _extractBindingEvents:&events];
+ }
+
+ Class clazz = NSClassFromString(config.clazz);;
+ WXComponent *component = [[clazz alloc] initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:self.weexInstance];
+ if (isTemplate) {
+ component->_isTemplate = YES;
+ [component _storeBindingsWithProps:bindingProps styles:bindingStyles attributes:bindingAttibutes events:bindingEvents];
+ }
+
+ WXAssert(component, @"Component build failed for data:%@", data);
+
+ [_indexDict setObject:component forKey:component.ref];
+ [component readyToRender];// notify redyToRender event when init
+ return component;
+}
+
+- (void)addComponent:(WXComponent *)component toIndexDictForRef:(NSString *)ref
+{
+ [_indexDict setObject:component forKey:ref];
+}
+
+- (NSDictionary *)_extractBindings:(NSDictionary **)attributesOrStylesPoint
+{
+ NSDictionary *attributesOrStyles = *attributesOrStylesPoint;
+ if (!attributesOrStyles) {
+ return nil;
+ }
+
+ NSMutableDictionary *newAttributesOrStyles = [attributesOrStyles mutableCopy];
+ NSMutableDictionary *bindingAttributesOrStyles = [NSMutableDictionary dictionary];
+
+ [attributesOrStyles enumerateKeysAndObjectsUsingBlock:^(id _Nonnull attributeOrStyleName, id _Nonnull attributeOrStyle, BOOL * _Nonnull stop) {
+ if ([WXBindingMatchIdentify isEqualToString:attributeOrStyleName] // match
+ || [WXBindingRepeatIdentify isEqualToString:attributeOrStyleName] // repeat
+ || [WXBindingOnceIdentify isEqualToString:attributeOrStyleName] // once
+ ||([attributeOrStyle isKindOfClass:[NSDictionary class]] && attributeOrStyle[WXBindingIdentify])) { // {"attributeOrStyleName": {"@binding":"bindingExpression"}
+ bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
+ [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
+ } else if ([attributeOrStyle isKindOfClass:[NSArray class]]) {
+ // {"attributeOrStyleName":[..., "string", {"@binding":"bindingExpression"}, "string", {"@binding":"bindingExpression"}, ...]
+ __block BOOL isBinding = NO;
+ [attributeOrStyle enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+ if ([obj isKindOfClass:[NSDictionary class]] && obj[WXBindingIdentify]) {
+ isBinding = YES;
+ *stop = YES;
+ }
+ }];
+
+ if (isBinding) {
+ bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
+ [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
+ }
+ }
+ }];
+
+ *attributesOrStylesPoint = newAttributesOrStyles;
+
+ return bindingAttributesOrStyles;
+}
+
+- (NSDictionary *)_extractBindingEvents:(NSArray **)eventsPoint
+{
+ NSArray *events = *eventsPoint;
+ NSMutableArray *newEvents = [events mutableCopy];
+ NSMutableDictionary *bindingEvents = [NSMutableDictionary dictionary];
+ [events enumerateObjectsUsingBlock:^(id _Nonnull event, NSUInteger idx, BOOL * _Nonnull stop) {
+ if ([event isKindOfClass:[NSDictionary class]] && event[@"type"] && event[@"params"]) {
+ NSString *eventName = event[@"type"];
+ NSString *bindingParams = event[@"params"];
+ bindingEvents[eventName] = bindingParams;
+ newEvents[idx] = eventName;
+ }
+ }];
+
+ *eventsPoint = newEvents;
+ return bindingEvents;
+}
+
+- (NSDictionary *)_extractBindingProps:(NSDictionary **)attributesPoint
+{
+ NSDictionary *attributes = *attributesPoint;
+ if (attributes[@"@componentProps"]) {
+ NSMutableDictionary *newAttributes = [attributes mutableCopy];
+ [newAttributes removeObjectForKey:@"@componentProps"];
+ *attributesPoint = newAttributes;
+ return attributes[@"@componentProps"];
+ }
+
+ return nil;
+}
+
+#pragma mark Reset
+-(BOOL)isShouldReset:(id )value
+{
+ if([value isKindOfClass:[NSString class]]) {
+ if(!value || [@"" isEqualToString:value]) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+-(void)filterStyles:(NSDictionary *)styles normalStyles:(NSMutableDictionary *)normalStyles resetStyles:(NSMutableArray *)resetStyles
+{
+ for (NSString *key in styles) {
+ id value = [styles objectForKey:key];
+ if([self isShouldReset:value]) {
+ [resetStyles addObject:key];
+ }else{
+ [normalStyles setObject:styles[key] forKey:key];
+ }
+ }
+}
+
+- (void)updateStyles:(NSDictionary *)styles forComponent:(NSString *)ref
+{
+ [self handleStyles:styles forComponent:ref isUpdateStyles:YES];
+}
+
+- (void)updatePseudoClassStyles:(NSDictionary *)styles forComponent:(NSString *)ref
+{
+ [self handleStyles:styles forComponent:ref isUpdateStyles:NO];
+}
+
+- (void)handleStyleOnMainThread:(NSDictionary*)styles forComponent:(WXComponent *)component isUpdateStyles:(BOOL)isUpdateStyles
+{
+ WXAssertParam(styles);
+ WXAssertParam(component);
+ WXAssertMainThread();
+
+ NSMutableDictionary *normalStyles = [NSMutableDictionary new];
+ NSMutableArray *resetStyles = [NSMutableArray new];
+ [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
+ [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
+ [component readyToRender];
+
+ WXPerformBlockOnComponentThread(^{
+ [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
+ });
+}
+
+- (void)handleStyles:(NSDictionary *)styles forComponent:(NSString *)ref isUpdateStyles:(BOOL)isUpdateStyles
+{
+ WXAssertParam(styles);
+ WXAssertParam(ref);
+
+ WXComponent *component = [_indexDict objectForKey:ref];
+ WXAssertComponentExist(component);
+
+ NSMutableDictionary *normalStyles = [NSMutableDictionary new];
+ NSMutableArray *resetStyles = [NSMutableArray new];
+ [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
+ [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
+ [self _addUITask:^{
+ [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
+ [component readyToRender];
+ }];
+}
+
+- (void)updateAttributes:(NSDictionary *)attributes forComponent:(NSString *)ref
+{
+ WXAssertParam(attributes);
+ WXAssertParam(ref);
+
+ WXComponent *component = [_indexDict objectForKey:ref];
+ WXAssertComponentExist(component);
+
+ [component _updateAttributesOnComponentThread:attributes];
+ __weak typeof(self) weakSelf = self;
+ [self _addUITask:^{
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
+ [component _updateAttributesOnMainThread:attributes];
+ [component readyToRender];
+ [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
+ }];
+}
+
+- (void)addEvent:(NSString *)eventName toComponent:(NSString *)ref
+{
+ WXAssertComponentThread();
+ WXAssertParam(eventName);
+ WXAssertParam(ref);
+
+ WXComponent *component = [_indexDict objectForKey:ref];
+ WXAssertComponentExist(component);
+
+ [component _addEventOnComponentThread:eventName];
+
+ [self _addUITask:^{
+ [component _addEventOnMainThread:eventName];
+ }];
+}
+
+- (void)removeEvent:(NSString *)eventName fromComponent:(NSString *)ref
+{
+ WXAssertComponentThread();
+ WXAssertParam(eventName);
+ WXAssertParam(ref);
+
+ WXComponent *component = [_indexDict objectForKey:ref];
+ WXAssertComponentExist(component);
+
+ [component _removeEventOnComponentThread:eventName];
+
+ [self _addUITask:^{
+ [component _removeEventOnMainThread:eventName];
+ }];
+}
+
+- (void)scrollToComponent:(NSString *)ref options:(NSDictionary *)options
+{
+ WXAssertComponentThread();
+ WXAssertParam(ref);
+
+ WXComponent *toComponent = [_indexDict objectForKey:ref];
+ WXAssertComponentExist(toComponent);
+
+ id<WXScrollerProtocol> scrollerComponent = toComponent.ancestorScroller;
+ if (!scrollerComponent) {
+ return;
+ }
+
+ CGFloat offset = [[options objectForKey:@"offset"] floatValue];
+ BOOL animated = YES;
+ if ([options objectForKey:@"animated"]) {
+ animated = [[options objectForKey:@"animated"] boolValue];
+ }
+
+ [self _addUITask:^{
+ [scrollerComponent scrollToComponent:toComponent withOffset:offset animated:animated];
+ }];
+}
+
+#pragma mark Life Cycle
+
+- (void)createFinish
+{
+ WXAssertComponentThread();
+
+ WXSDKInstance *instance = self.weexInstance;
+ [self _addUITask:^{
+ UIView *rootView = instance.rootView;
+
+ //WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, instance);
+ WX_MONITOR_INSTANCE_PERF_END(WXPTAllRender, instance);
+ WX_MONITOR_SUCCESS(WXMTJSBridge);
+ WX_MONITOR_SUCCESS(WXMTNativeRender);
+
+ if(instance.renderFinish){
+ [WXTracingManager startTracingWithInstanceId:instance.instanceId ref:nil className:nil name:nil phase:WXTracingInstant functionName:WXTRenderFinish options:@{@"threadName":WXTUIThread}];
+ instance.renderFinish(rootView);
+ }
+ }];
+ [instance updatePerDicAfterCreateFinish];
+}
+
+- (void)updateFinish
+{
+ WXAssertComponentThread();
+
+ WXSDKInstance *instance = self.weexInstance;
+ WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
+
+ [self _addUITask:^{
+ if(instance.updateFinish){
+ instance.updateFinish(root.view);
+ }
+ }];
+}
+
+- (void)refreshFinish
+{
+ WXAssertComponentThread();
+
+ WXSDKInstance *instance = self.weexInstance;
+ WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
+
+ [self _addUITask:^{
+ if(instance.refreshFinish){
+ instance.refreshFinish(root.view);
+ }
+ }];
+}
+
+- (void)unload
+{
+ WXAssertComponentThread();
+ [self invalidate];
+ [self _stopDisplayLink];
+ NSEnumerator *enumerator = [[_indexDict copy] objectEnumerator];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ WXComponent *component;
+ while ((component = [enumerator nextObject])) {
+ [component _unloadViewWithReusing:NO];
+ }
+ _rootComponent = nil;
+ });
+
+ [_indexDict removeAllObjects];
+ [_uiTaskQueue removeAllObjects];
+}
+
+- (void)invalidate
+{
+ _isValid = NO;
+}
+
+- (BOOL)isValid
+{
+ return _isValid;
+}
+
+#pragma mark Layout Batch
+
+- (void)_startDisplayLink
+{
+ WXAssertComponentThread();
+
+ if(!_displayLink){
+ _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleDisplayLink)];
+ [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
+ }
+}
+
+- (void)_stopDisplayLink
+{
+ WXAssertComponentThread();
+
+ if(_displayLink){
+ [_displayLink invalidate];
+ _displayLink = nil;
+ }
+}
+
+- (void)_suspendDisplayLink
+{
+ WXAssertComponentThread();
+
+ if(_displayLink && !_displayLink.paused) {
+ _displayLink.paused = YES;
+ }
+}
+
+- (void)_awakeDisplayLink
+{
+ WXAssertComponentThread();
+
+ if(_displayLink && _displayLink.paused) {
+ _displayLink.paused = NO;
+ }
+}
+
+- (void)_handleDisplayLink
+{
+ WXAssertComponentThread();
+
+ [self _layoutAndSyncUI];
+}
+
+- (void)_layoutAndSyncUI
+{
+ [self _layout];
+ if(_uiTaskQueue.count > 0){
+ [self _syncUITasks];
+ _noTaskTickCount = 0;
+ } else {
+ // suspend display link when there's no task for 1 second, in order to save CPU time.
+ _noTaskTickCount ++;
+ if (_noTaskTickCount > 60) {
+ [self _suspendDisplayLink];
+ }
+ }
+}
+
+- (void)_layout
+{
+ BOOL needsLayout = NO;
+
+// NSEnumerator *enumerator = [_indexDict objectEnumerator];
+// WXComponent *component;
+// while ((component = [enumerator nextObject])) {
+// if ([component needsLayout]) {
+// needsLayout = YES;
+// break;
+// }
+// }
+
+ needsLayout = [_rootComponent needsLayout];
+
+ if (!needsLayout) {
+ return;
+ }
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> action__ calculateLayout root");
+#endif
+
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ layoutNode(_rootCSSNode, _rootCSSNode->style.dimensions[CSS_WIDTH], _rootCSSNode->style.dimensions[CSS_HEIGHT], CSS_DIRECTION_INHERIT);
+ }
+//#else
+ else
+ {
+ std::pair<float, float> renderPageSize;
+ renderPageSize.first = self.weexInstance.frame.size.width;
+ renderPageSize.second = self.weexInstance.frame.size.height;
+ _rootFlexCSSNode->calculateLayout(renderPageSize);
+ }
+//#endif
+ NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
+ [_rootComponent _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
+ [self _calculateRootFrame];
+
+ for (WXComponent *dirtyComponent in dirtyComponents) {
+ [self _addUITask:^{
+ [dirtyComponent _layoutDidFinish];
+ }];
+ }
+}
+
+//#ifdef USE_FLEX
+- (void) _printFlexComonentFrame:(WXComponent *)component
+{
+#ifdef DEBUG
+ WXLogDebug(@"node ref:%@, type:%@ , frame:%@",
+ component.ref,
+ component.type,
+ NSStringFromCGRect(component.view.layer.frame)
+ );
+#endif
+
+
+
+ for (WXComponent *childComponent in component.subcomponents) {
+ [self _printFlexComonentFrame:childComponent];
+ }
+
+
+}
+//#endif
+
+- (void)_syncUITasks
+{
+ NSArray<dispatch_block_t> *blocks = _uiTaskQueue;
+ _uiTaskQueue = [NSMutableArray array];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ for(dispatch_block_t block in blocks) {
+ block();
+ }
+ });
+}
+//#ifndef USE_FLEX
+- (void)_initRootCSSNode
+{
+ _rootCSSNode = new_css_node();
+
+ [self _applyRootFrame:self.weexInstance.frame toRootCSSNode:_rootCSSNode];
+
+ _rootCSSNode->style.flex_wrap = CSS_NOWRAP;
+ _rootCSSNode->is_dirty = rootNodeIsDirty;
+ _rootCSSNode->get_child = rootNodeGetChild;
+ _rootCSSNode->context=(__bridge void *)(self);
+ _rootCSSNode->children_count = 1;
+}
+//#else
+- (void)_initRootFlexCssNode
+{
+ _rootFlexCSSNode = new WeexCore::WXCoreLayoutNode();
+ [self _applyRootFrame:self.weexInstance.frame];
+ _rootFlexCSSNode->setFlexWrap(WeexCore::kNoWrap);
+ _rootFlexCSSNode->setContext((__bridge void *)(self));
+}
+//#endif
+
+- (void)_calculateRootFrame
+{
+//#ifndef USE_FLEX
+
+ if(![WXComponent isUseFlex])
+ {
+ if (!_rootCSSNode->layout.should_update) {
+ return;
+ }
+ _rootCSSNode->layout.should_update = false;
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> root _calculateRootFrame");
+#endif
+
+ CGRect frame = CGRectMake(WXRoundPixelValue(_rootCSSNode->layout.position[CSS_LEFT]),
+ WXRoundPixelValue(_rootCSSNode->layout.position[CSS_TOP]),
+ WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_WIDTH]),
+ WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_HEIGHT]));
+ WXPerformBlockOnMainThread(^{
+ if(!self.weexInstance.isRootViewFrozen) {
+ self.weexInstance.rootView.frame = frame;
+ }
+ });
+
+ resetNodeLayout(_rootCSSNode);
+ }
+//#else
+ else
+ {
+ if(!_rootFlexCSSNode->hasNewLayout()){
+ return;
+ }
+ _rootFlexCSSNode->setHasNewLayout(false);
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> root _calculateRootFrame");
+#endif
+
+
+ CGRect frame = CGRectMake(WXRoundPixelValue(_rootFlexCSSNode->getLayoutPositionLeft()),
+ WXRoundPixelValue(_rootFlexCSSNode->getLayoutPositionTop()),
+ WXRoundPixelValue(_rootFlexCSSNode->getLayoutWidth()),
+ WXRoundPixelValue(_rootFlexCSSNode->getLayoutHeight()));
+ WXPerformBlockOnMainThread(^{
+ if(!self.weexInstance.isRootViewFrozen) {
+ self.weexInstance.rootView.frame = frame;
+ }
+ });
+ // _rootFlexCSSNode->reset();
+
+ // resetNodeLayout(_rootFlexCSSNode);
+ }
+//#endif
+
+
+}
+
+
+#pragma mark Fixed
+
+- (void)addFixedComponent:(WXComponent *)fixComponent
+{
+ [_fixedComponents addObject:fixComponent];
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
+ }
+//#else
+ else
+ {
+ _rootFlexCSSNode->addChildAt(fixComponent.flexCssNode, (uint32_t)([_fixedComponents count]-1));
+ }
+//#endif
+}
+
+- (void)removeFixedComponent:(WXComponent *)fixComponent
+{
+ [_fixedComponents removeObject:fixComponent];
+//#ifndef USE_FLEX
+ if(![WXComponent isUseFlex])
+ {
+ _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
+ }
+//#else
+ else
+ {
+ _rootFlexCSSNode->removeChild(fixComponent->_flexCssNode);
+ }
+//#endif
+}
+
+@end
+
+void WXPerformBlockOnComponentThread(void (^block)(void))
+{
+ [WXComponentManager _performBlockOnComponentThread:block];
+}
+
+void WXPerformBlockSyncOnComponentThread(void (^block)(void))
+{
+ [WXComponentManager _performBlockSyncOnComponentThread:block];
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.h b/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
index 5e8ba70..c0e6c9a 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.h
@@ -17,6 +17,12 @@
* under the License.
*/
+/**
+ * def : use weex_flex_engin
+ * ndef: use yoga
+ **/
+
+
#import <Foundation/Foundation.h>
#import "WXLayoutDefine.h"
#import "WXType.h"
@@ -143,13 +149,6 @@ NS_ASSUME_NONNULL_BEGIN
//@property(nonatomic, assign) CGPoint absolutePosition;
/**
- * @abstract Return the css node used to layout.
- *
- * @warning Subclasses must not override this.
- */
-@property(nonatomic, readonly, assign) css_node_t *cssNode;
-
-/**
* @abstract Invalidates the component's layout and marks it as needing an update.
*
* @discussion You can call this method to indicate that the layout of a component has changed and must be updated. Weex typically calls this method automatically when the layout-related styles change or when subcomponents are added or removed.
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m b/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
deleted file mode 100644
index 300dbc9..0000000
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 "WXComponent.h"
-#import "WXComponent_internal.h"
-#import "WXComponentManager.h"
-#import "WXSDKManager.h"
-#import "WXSDKInstance.h"
-#import "WXSDKInstance_private.h"
-#import "WXDefine.h"
-#import "WXLog.h"
-#import "WXWeakObjectWrapper.h"
-#import "WXUtility.h"
-#import "WXConvert.h"
-#import "WXMonitor.h"
-#import "WXAssert.h"
-#import "WXThreadSafeMutableDictionary.h"
-#import "WXThreadSafeMutableArray.h"
-#import "WXTransform.h"
-#import "WXRoundedRect.h"
-#import <pthread/pthread.h>
-#import "WXComponent+PseudoClassManagement.h"
-#import "WXComponent+BoxShadow.h"
-#import "WXTracingManager.h"
-#import "WXComponent+Events.h"
-
-#pragma clang diagnostic ignored "-Wincomplete-implementation"
-#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
-
-@interface WXComponent () <UIGestureRecognizerDelegate>
-
-@end
-
-@implementation WXComponent
-{
-@private
- NSString *_ref;
- NSMutableDictionary *_styles;
- NSMutableDictionary *_attributes;
- NSMutableArray *_events;
-
- // Protects properties styles/attributes/events/subcomponents which will be accessed from multiple threads.
- pthread_mutex_t _propertyMutex;
- pthread_mutexattr_t _propertMutexAttr;
-
- __weak WXComponent *_supercomponent;
- __weak id<WXScrollerProtocol> _ancestorScroller;
- __weak WXSDKInstance *_weexInstance;
-}
-
-#pragma mark Life Cycle
-
-- (instancetype)initWithRef:(NSString *)ref
- type:(NSString *)type
- styles:(NSDictionary *)styles
- attributes:(NSDictionary *)attributes
- events:(NSArray *)events
- weexInstance:(WXSDKInstance *)weexInstance
-{
- if (self = [super init]) {
- pthread_mutexattr_init(&_propertMutexAttr);
- pthread_mutexattr_settype(&_propertMutexAttr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&_propertyMutex, &_propertMutexAttr);
-
- _ref = ref;
- _type = type;
- _weexInstance = weexInstance;
- _componentType = WXComponentTypeCommon;
- _styles = [self parseStyles:styles];
- _attributes = attributes ? [NSMutableDictionary dictionaryWithDictionary:attributes] : [NSMutableDictionary dictionary];
- _events = events ? [NSMutableArray arrayWithArray:events] : [NSMutableArray array];
- _subcomponents = [NSMutableArray array];
- _absolutePosition = CGPointMake(NAN, NAN);
-
- _displayType = WXDisplayTypeBlock;
- _isNeedJoinLayoutSystem = YES;
- _isLayoutDirty = YES;
- _isViewFrameSyncWithCalculated = YES;
- _ariaHidden = nil;
- _accessible = nil;
- _accessibilityHintContent = nil;
-
- _async = NO;
-
- if (styles[kWXTransitionProperty]) {
- _transition = [[WXTransition alloc]initWithStyles:styles];
- }
-
- //TODO set indicator style
- if ([type isEqualToString:@"indicator"]) {
- _styles[@"position"] = @"absolute";
- if (!_styles[@"left"] && !_styles[@"right"]) {
- _styles[@"left"] = @0.0f;
- }
- if (!_styles[@"top"] && !_styles[@"bottom"]) {
- _styles[@"top"] = @0.0f;
- }
- }
-
- if (attributes[@"ariaHidden"]) {
-
- _ariaHidden = [WXConvert NSString:attributes[@"ariaHidden"]];
- }
- if (attributes[@"role"]) {
- _roles = attributes[@"role"];
- }
- if (attributes[@"ariaLabel"]) {
- _ariaLabel = [WXConvert NSString:attributes[@"ariaLabel"]];
- }
- if (attributes[@"accessible"]) {
- _accessible = [WXConvert NSString:attributes[@"accessible"]];
- }
- if(attributes[@"accessibilityHint"]) {
- _accessibilityHintContent = [WXConvert NSString:attributes[@"accessibilityHint"]];
- }
- if (attributes[@"groupAccessibilityChildren"]) {
- _groupAccessibilityChildren = [WXConvert NSString:attributes[@"groupAccessibilityChildren"]];
- }
-
- if (attributes[@"testId"]) {
- _testId = [WXConvert NSString:attributes[@"testId"]];
- }
-
- [self _setupNavBarWithStyles:_styles attributes:_attributes];
- [self _initCSSNodeWithStyles:_styles];
- [self _initViewPropertyWithStyles:_styles];
- [self _initCompositingAttribute:_attributes];
- [self _handleBorders:styles isUpdating:NO];
-
- }
-
- return self;
-}
-
-- (id)copyWithZone:(NSZone *)zone
-{
- NSInteger copyId = 0;
- @synchronized(self){
- static NSInteger __copy = 0;
- copyId = __copy % (1024*1024);
- __copy++;
- }
- NSString *copyRef = [NSString stringWithFormat:@"%ldcopy_of%@", (long)copyId, _isTemplate ? self.ref : self->_templateComponent.ref];
- WXComponent *component = [[[self class] allocWithZone:zone] initWithRef:copyRef type:self.type styles:self.styles attributes:self.attributes events:self.events weexInstance:self.weexInstance];
- if (_isTemplate) {
- component->_templateComponent = self;
- } else {
- component->_templateComponent = self->_templateComponent;
- }
- memcpy(component->_cssNode, self.cssNode, sizeof(css_node_t));
- component->_cssNode->context = (__bridge void *)component;
- component->_calculatedFrame = self.calculatedFrame;
-
- NSMutableArray *subcomponentsCopy = [NSMutableArray array];
- for (WXComponent *subcomponent in self.subcomponents) {
- WXComponent *subcomponentCopy = [subcomponent copy];
- subcomponentCopy->_supercomponent = component;
- [subcomponentsCopy addObject:subcomponentCopy];
- }
-
- component->_subcomponents = subcomponentsCopy;
-
- WXPerformBlockOnComponentThread(^{
- [self.weexInstance.componentManager addComponent:component toIndexDictForRef:copyRef];
- });
-
- return component;
-}
-
-- (UIAccessibilityTraits)_parseAccessibilityTraitsWithTraits:(UIAccessibilityTraits)trait roles:(NSString*)roleStr
-{
- UIAccessibilityTraits newTrait = trait;
- for (NSString * role in [roleStr componentsSeparatedByString:@" "]) {
- newTrait |= [WXConvert WXUIAccessibilityTraits: role];
- }
-
- return newTrait;
-}
-
-- (void)dealloc
-{
- free_css_node(_cssNode);
-
-// [self _removeAllEvents];
- // remove all gesture and all
- if (_isTemplate && self.attributes[@"@templateId"]) {
- [[WXSDKManager bridgeMgr] callComponentHook:_weexInstance.instanceId componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"destroy" args:nil competion:nil];
- }
- if (_tapGesture) {
- [_tapGesture removeTarget:nil action:NULL];
- }
- if ([_swipeGestures count]) {
- for (UISwipeGestureRecognizer *swipeGestures in _swipeGestures) {
- [swipeGestures removeTarget:nil action:NULL];
- }
- }
-
- if (_longPressGesture) {
- [_longPressGesture removeTarget:nil action:NULL];
- }
-
- if (_panGesture) {
- [_panGesture removeTarget:nil action:NULL];
- }
-
- if (_positionType == WXPositionTypeFixed) {
- [self.weexInstance.componentManager removeFixedComponent:self];
- }
-
- pthread_mutex_destroy(&_propertyMutex);
- pthread_mutexattr_destroy(&_propertMutexAttr);
-
-}
-
-- (NSDictionary *)styles
-{
- NSDictionary *styles;
- pthread_mutex_lock(&_propertyMutex);
- styles = _styles;
- pthread_mutex_unlock(&_propertyMutex);
- return styles;
-}
-
-- (NSDictionary *)pseudoClassStyles
-{
- NSDictionary *pseudoClassStyles;
- pthread_mutex_lock(&_propertyMutex);
- pseudoClassStyles = _pseudoClassStyles;
- pthread_mutex_unlock(&_propertyMutex);
-
- return pseudoClassStyles;
-}
-
-- (NSString *)type
-{
- return _type;
-}
-
-- (NSDictionary *)attributes
-{
- NSDictionary *attributes;
- pthread_mutex_lock(&_propertyMutex);
- attributes = _attributes;
- pthread_mutex_unlock(&_propertyMutex);
-
- return attributes;
-}
-
-- (NSArray *)events
-{
- NSArray *events;
- pthread_mutex_lock(&_propertyMutex);
- events = [_events copy];
- pthread_mutex_unlock(&_propertyMutex);
-
- return events;
-}
-
-- (void)setDisplayType:(WXDisplayType)displayType
-{
- if (_displayType != displayType) {
- _displayType = displayType;
- if (displayType == WXDisplayTypeNone) {
- _isNeedJoinLayoutSystem = NO;
- [self.supercomponent _recomputeCSSNodeChildren];
- WXPerformBlockOnMainThread(^{
- [self removeFromSuperview];
- });
- } else {
- _isNeedJoinLayoutSystem = YES;
- [self.supercomponent _recomputeCSSNodeChildren];
- WXPerformBlockOnMainThread(^{
- [self _buildViewHierarchyLazily];
- // TODO: insert into the correct index
- [self.supercomponent.view addSubview:self.view];
- });
- }
- [self setNeedsLayout];
- }
-}
-
-- (WXSDKInstance *)weexInstance
-{
- return _weexInstance;
-}
-
-- (NSString *)description
-{
- return [NSString stringWithFormat:@"<%@:%p ref=%@> %@", _type, self, _ref, _view];
-}
-
-#pragma mark Property
-
-- (UIView *)view
-{
- if (_componentType != WXComponentTypeCommon) {
- return nil;
- }
- if ([self isViewLoaded]) {
- return _view;
- } else {
- WXAssertMainThread();
-
- // compositing child will be drew by its composited ancestor
- if (_isCompositingChild) {
- return nil;
- }
-
- [self viewWillLoad];
-
- _view = [self loadView];
-
- _layer = _view.layer;
- _view.frame = _calculatedFrame;
- _view.hidden = _visibility == WXVisibilityShow ? NO : YES;
- _view.clipsToBounds = _clipToBounds;
- if (![self _needsDrawBorder]) {
- _layer.borderColor = _borderTopColor.CGColor;
- _layer.borderWidth = _borderTopWidth;
- [self _resetNativeBorderRadius];
- _layer.opacity = _opacity;
- _view.backgroundColor = _backgroundColor;
- }
-
- if (_backgroundImage) {
- [self setGradientLayer];
- }
-
- if (_transform) {
- [_transform applyTransformForView:_view];
- }
-
- if (_boxShadow) {
- [self configBoxShadow:_boxShadow];
- }
-
- _view.wx_component = self;
- _view.wx_ref = self.ref;
- _layer.wx_component = self;
-
- if (_roles) {
- [_view setAccessibilityTraits:[self _parseAccessibilityTraitsWithTraits:self.view.accessibilityTraits roles:_roles]];
- }
-
- if (_testId) {
- _view.accessibilityIdentifier = _testId;
- }
-
- if (_accessibilityHintContent) {
- [_view setAccessibilityHint:_accessibilityHintContent];
- }
-
- if (_ariaLabel) {
- _view.accessibilityLabel = _ariaLabel;
- }
- if (_accessible) {
- [_view setIsAccessibilityElement:[WXConvert BOOL:_accessible]];
- }
-
- if (_ariaHidden) {
- [_view setAccessibilityElementsHidden:[WXConvert BOOL:_ariaHidden]];
- }
- if (_groupAccessibilityChildren) {
- [_view setShouldGroupAccessibilityChildren:[WXConvert BOOL:_groupAccessibilityChildren]];
- }
-
- [self _initEvents:self.events];
- [self _initPseudoEvents:_isListenPseudoTouch];
-
- if (_positionType == WXPositionTypeSticky) {
- [self.ancestorScroller addStickyComponent:self];
- }
-
- if (self.supercomponent && self.supercomponent->_async) {
- self->_async = YES;
- }
-
- [self setNeedsDisplay];
- [[NSNotificationCenter defaultCenter] postNotificationName:WX_COMPONENT_NOTIFICATION_VIEW_LOADED object:self];
- [self viewDidLoad];
-
- if (_lazyCreateView) {
- [self _buildViewHierarchyLazily];
- }
-
- [self _handleFirstScreenTime];
-
- return _view;
- }
-}
-
-- (void)_buildViewHierarchyLazily
-{
- if (self.supercomponent && !((WXComponent *)self.supercomponent)->_lazyCreateView) {
- NSArray *subcomponents = ((WXComponent *)self.supercomponent).subcomponents;
-
- NSInteger index = [subcomponents indexOfObject:self];
- if (index != NSNotFound) {
- [(WXComponent *)self.supercomponent insertSubview:self atIndex:index];
- }
- }
-
- NSArray *subcomponents = self.subcomponents;
- for (int i = 0; i < subcomponents.count; i++) {
- WXComponent *subcomponent = subcomponents[i];
- [self insertSubview:subcomponent atIndex:i];
- }
-}
-
-- (void)_resetNativeBorderRadius
-{
- WXRoundedRect *borderRect = [[WXRoundedRect alloc] initWithRect:_calculatedFrame topLeft:_borderTopLeftRadius topRight:_borderTopRightRadius bottomLeft:_borderBottomLeftRadius bottomRight:_borderBottomRightRadius];
- _layer.cornerRadius = borderRect.radii.topLeft;
-}
-
-- (void)_handleFirstScreenTime
-{
- if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance)) {
- return;
- }
- CGPoint absolutePosition = [self.supercomponent.view convertPoint:_view.frame.origin toView:_weexInstance.rootView];
- if (absolutePosition.y + _view.frame.size.height > self.weexInstance.rootView.frame.size.height + 1) {
- WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance);
- }
-}
-
-- (CALayer *)layer
-{
- return _layer;
-}
-
-- (CGRect)calculatedFrame
-{
- return _calculatedFrame;
-}
-
-- (CGPoint)absolutePosition
-{
- return _absolutePosition;
-}
-
-- (css_node_t *)cssNode
-{
- return _cssNode;
-}
-
-- (void)_addEventParams:(NSDictionary *)params
-{
- pthread_mutex_lock(&_propertyMutex);
- if (!_eventParameters) {
- _eventParameters = [NSMutableDictionary dictionary];
- }
- [_eventParameters addEntriesFromDictionary:params];
- pthread_mutex_unlock(&_propertyMutex);
-}
-
-- (NSArray *)_paramsForEvent:(NSString *)eventName
-{
- NSArray *params;
- pthread_mutex_lock(&_propertyMutex);
- params = _eventParameters[eventName];
- pthread_mutex_unlock(&_propertyMutex);
-
- return params;
-}
-
-#pragma mark Component Hierarchy
-
-- (NSArray<WXComponent *> *)subcomponents
-{
- NSArray<WXComponent *> *subcomponents;
- pthread_mutex_lock(&_propertyMutex);
- subcomponents = [_subcomponents copy];
- pthread_mutex_unlock(&_propertyMutex);
-
- return subcomponents;
-}
-
-- (WXComponent *)supercomponent
-{
- return _supercomponent;
-}
-
-- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
-{
- WXAssert(subcomponent, @"The subcomponent to insert to %@ at index %d must not be nil", self, index);
- if (index > [_subcomponents count]) {
- WXLogError(@"the index of inserted %ld is out of range as the current is %lu", (long)index, (unsigned long)[_subcomponents count]);
- return;
- }
-
- subcomponent->_supercomponent = self;
-
- pthread_mutex_lock(&_propertyMutex);
- [_subcomponents insertObject:subcomponent atIndex:index];
- pthread_mutex_unlock(&_propertyMutex);
-
- if (subcomponent->_positionType == WXPositionTypeFixed) {
- [self.weexInstance.componentManager addFixedComponent:subcomponent];
- subcomponent->_isNeedJoinLayoutSystem = NO;
- }
-
- if (_useCompositing || _isCompositingChild) {
- subcomponent->_isCompositingChild = YES;
- }
-
- [self _recomputeCSSNodeChildren];
- [self setNeedsLayout];
-}
-
-- (void)_removeSubcomponent:(WXComponent *)subcomponent
-{
- pthread_mutex_lock(&_propertyMutex);
- [_subcomponents removeObject:subcomponent];
- pthread_mutex_unlock(&_propertyMutex);
-}
-
-- (void)_removeFromSupercomponent
-{
- [self.supercomponent _removeSubcomponent:self];
- [self.supercomponent _recomputeCSSNodeChildren];
- [self.supercomponent setNeedsLayout];
-
- if (_positionType == WXPositionTypeFixed) {
- [self.weexInstance.componentManager removeFixedComponent:self];
- self->_isNeedJoinLayoutSystem = YES;
- }
-}
-
-- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index
-{
- [self _removeFromSupercomponent];
- [newSupercomponent _insertSubcomponent:self atIndex:index];
-}
-
-- (void)_didInserted
-{
-
-}
-
-- (id<WXScrollerProtocol>)ancestorScroller
-{
- if(!_ancestorScroller) {
- WXComponent *supercomponent = self.supercomponent;
- while (supercomponent) {
- if([supercomponent conformsToProtocol:@protocol(WXScrollerProtocol)]) {
- _ancestorScroller = (id<WXScrollerProtocol>)supercomponent;
- break;
- }
- supercomponent = supercomponent.supercomponent;
- }
- }
-
- return _ancestorScroller;
-}
-
-#pragma mark Updating
-- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles
-{
- BOOL isTransitionTag = _transition ? [self _isTransitionTag:styles] : NO;
- if (isTransitionTag) {
- [_transition _handleTransitionWithStyles:styles resetStyles:resetStyles target:self];
- } else {
- styles = [self parseStyles:styles];
- [self _updateCSSNodeStyles:styles];
- [self _resetCSSNodeStyles:resetStyles];
- }
- if (isUpdateStyles) {
- [self _modifyStyles:styles];
- if ([self needsLayout]) {
- // call update style may take effect on layout, maybe the component
- // displaylink has been paused, so we need to restart the component task, and it will auto-pause when task queue is empty.
- [self.weexInstance.componentManager startComponentTasks];
- }
- }
-}
-
-- (BOOL)_isTransitionTag:(NSDictionary *)styles
-{
- BOOL yesOrNo = false;
- if (_transition.transitionOptions != WXTransitionOptionsNone) {
- yesOrNo = true;
- }
- return yesOrNo;
-}
-
-- (BOOL)_isTransitionOnMainThreadStyles:(NSDictionary *)styles
-{
- BOOL yesOrNo = false;
- if (_transition.transitionOptions != WXTransitionOptionsNone) {
- if ((_transition.transitionOptions & WXTransitionOptionsBackgroundColor &&styles[@"backgroundColor"])
- ||(_transition.transitionOptions & WXTransitionOptionsTransform &&styles[@"transform"])
- ||(_transition.transitionOptions & WXTransitionOptionsOpacity &&styles[@"opacity"])) {
- yesOrNo = true;
- }
- }
- return yesOrNo;
-}
-
-- (void)_modifyStyles:(NSDictionary *)styles
-{
- pthread_mutex_lock(&_propertyMutex);
- [_styles addEntriesFromDictionary:styles];
- pthread_mutex_unlock(&_propertyMutex);
-}
-
-- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes
-{
- pthread_mutex_lock(&_propertyMutex);
- [_attributes addEntriesFromDictionary:attributes];
- pthread_mutex_unlock(&_propertyMutex);
-}
-
-- (void)_addEventOnComponentThread:(NSString *)eventName
-{
- pthread_mutex_lock(&_propertyMutex);
- [_events addObject:eventName];
- pthread_mutex_unlock(&_propertyMutex);
-}
-
-- (void)_removeEventOnComponentThread:(NSString *)eventName
-{
- pthread_mutex_lock(&_propertyMutex);
- [_events removeObject:eventName];
- pthread_mutex_unlock(&_propertyMutex);
-}
-
-- (void)_updateStylesOnMainThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles
-{
- WXAssertMainThread();
- if (![self _isTransitionOnMainThreadStyles:styles]) {
- [self _updateViewStyles:styles];
- } else {
- [self _transitionUpdateViewProperty:styles];
- }
- [self _resetStyles:resetStyles];
- [self _handleBorders:styles isUpdating:YES];
- [self updateStyles:styles];
- [self resetStyles:resetStyles];
-}
-
-- (void)_updateAttributesOnMainThread:(NSDictionary *)attributes
-{
- WXAssertMainThread();
-
- [self _updateNavBarAttributes:attributes];
-
- [self updateAttributes:attributes];
- [self _configWXComponentA11yWithAttributes:attributes];
-}
-
-- (void)updateStyles:(NSDictionary *)styles
-{
- WXAssertMainThread();
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes
-{
- WXAssertMainThread();
-}
-
-- (void)setNativeTransform:(CGAffineTransform)transform
-{
- WXAssertMainThread();
-
- _transform = [[WXTransform alloc] initWithNativeTransform:CATransform3DMakeAffineTransform(transform) instance:self.weexInstance];
- if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
- [_transform applyTransformForView:_view];
- [_layer setNeedsDisplay];
- }
-}
-
-- (void)readyToRender
-{
- if (self.weexInstance.trackComponent) {
- [self.supercomponent readyToRender];
- }
-}
-
-
-- (void)setGradientLayer
-{
- if (CGRectEqualToRect(self.view.frame, CGRectZero)) {
- return;
- }
- NSDictionary * linearGradient = [WXUtility linearGradientWithBackgroundImage:_backgroundImage];
- if (!linearGradient) {
- return ;
- }
-
- __weak typeof(self) weakSelf = self;
- dispatch_async(dispatch_get_main_queue(), ^{
- __strong typeof(self) strongSelf = weakSelf;
- if(strongSelf) {
- UIColor * startColor = (UIColor*)linearGradient[@"startColor"];
- UIColor * endColor = (UIColor*)linearGradient[@"endColor"];
- CAGradientLayer * gradientLayer = [WXUtility gradientLayerFromColors:@[startColor, endColor] locations:nil frame:strongSelf.view.bounds gradientType:[linearGradient[@"gradientType"] integerValue]];
- if (gradientLayer) {
- _backgroundColor = [UIColor colorWithPatternImage:[strongSelf imageFromLayer:gradientLayer]];
- strongSelf.view.backgroundColor = _backgroundColor;
- }
- }
- });
-}
-
-- (void)_configWXComponentA11yWithAttributes:(NSDictionary *)attributes
-{
- WX_CHECK_COMPONENT_TYPE(self.componentType)
- if (attributes[@"role"]){
- _roles = attributes[@"role"];
- [self.view setAccessibilityTraits:[self _parseAccessibilityTraitsWithTraits:self.view.accessibilityTraits roles:_roles]];
- }
- if (attributes[@"ariaHidden"]) {
- _ariaHidden = [WXConvert NSString:attributes[@"ariaHidden"]];
- [self.view setAccessibilityElementsHidden:[WXConvert BOOL:_ariaHidden]];
- }
- if (attributes[@"accessible"]) {
- _accessible = [WXConvert NSString:attributes[@"accessible"]];
- [self.view setIsAccessibilityElement:[WXConvert BOOL:_accessible]];
- }
- if (attributes[@"ariaLabel"]) {
- _ariaLabel = [WXConvert NSString:attributes[@"ariaLabel"]];
- self.view.accessibilityValue = _ariaLabel;
- }
- if (attributes[@"accessibilityHint"]) {
- _accessibilityHintContent = [WXConvert NSString:attributes[@"accessibilityHint"]];
- [self.view setAccessibilityHint:_accessibilityHintContent];
- }
-
- if (attributes[@"groupAccessibilityChildren"]) {
- _groupAccessibilityChildren = [WXConvert NSString:attributes[@"groupAccessibilityChildren"]];
- [self.view setShouldGroupAccessibilityChildren:[WXConvert BOOL:_groupAccessibilityChildren]];
- }
-
-
- if (attributes[@"testId"]) {
- [self.view setAccessibilityIdentifier:[WXConvert NSString:attributes[@"testId"]]];
- }
-
-}
-
-- (UIImage *)imageFromLayer:(CALayer *)layer
-{
- UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, 0);
- [layer renderInContext:UIGraphicsGetCurrentContext()];
- UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return outputImage;
-}
-
-#pragma mark Reset
-- (void)resetStyles:(NSArray *)styles
-{
- WXAssertMainThread();
-}
-
-#pragma mark Layout
-
-/**
- * @see WXComponent+Layout.m
- */
-
-#pragma mark View Management
-
-/**
- * @see WXComponent+ViewManagement.m
- */
-
-#pragma mark Events
-
-/**
- * @see WXComponent+Events.m
- */
-
-#pragma mark Display
-
-/**
- * @see WXComponent+Display.m
- */
-
-@end
-
-
-@implementation UIView (WXComponent)
-
-- (WXComponent *)wx_component
-{
- WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_component));
- return [weakWrapper weakObject];
-}
-
-- (void)setWx_component:(WXComponent *)wx_component
-{
- id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_component];
- objc_setAssociatedObject(self, @selector(wx_component), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-}
-
-- (NSString *)wx_ref
-{
- WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_ref));
- return [weakWrapper weakObject];
-}
-
-- (void)setWx_ref:(NSString *)wx_ref
-{
- id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_ref];
- objc_setAssociatedObject(self, @selector(wx_ref), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-}
-
-@end
-
-@implementation CALayer (WXComponents_new)
-
-- (WXComponent *)wx_component
-{
- WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_component));
- return [weakWrapper weakObject];
-}
-
-- (void)setWx_component:(WXComponent *)wx_component
-{
- id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_component];
- objc_setAssociatedObject(self, @selector(wx_component), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-}
-
-@end