Repository: incubator-weex
Updated Branches:
  refs/heads/master 7984b16c7 -> e31458ac3


* [iOS] use the first cell-slot template while the templateType is not specified

* [iOS] support componentHook callJS method

* [iOS] create life-cycle for recycle-list component

* [iOS] support lifecycle about create, destroy, attach and detach

* [iOS] fix compiler complains

* [iOS] use switch and case for template selection

* [iOS] remove unused code

* [iOS] update read default case

* [iOS] support lifecycle for recycleList component

close #1023

* [iOS] add component method for operating data

* [iOS] bugfix

* [iOS] rename @componentId to @templateId

* [iOS] support v-once

* [iOS] support non-object in javaScript  on data

* [iOS] bugfix about insertRange on recycleList

* [iOS] formate data

* [iOS] add recycleListComponentRef for data

* [iOS] fix bug about v-once

* [iOS] log interrupt update info

* [iOS] bugfix about parse member property

* [iOS] bugfix about recyle-list

* [iOS] update playground version


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/e31458ac
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/e31458ac
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/e31458ac

Branch: refs/heads/master
Commit: e31458ac334446a1d83a8c424676bc8961bc960e
Parents: 7984b16
Author: acton393 <zhangxing610...@gmail.com>
Authored: Mon Dec 25 17:54:49 2017 +0800
Committer: acton393 <zhangxing610...@gmail.com>
Committed: Fri Feb 9 19:23:33 2018 +0800

----------------------------------------------------------------------
 ios/playground/WeexDemo/Info.plist              |   4 +-
 .../WeexSDK/Sources/Bridge/WXBridgeContext.h    |   3 +
 .../WeexSDK/Sources/Bridge/WXBridgeContext.m    |  27 +++
 .../Component/RecycleList/WXCellSlotComponent.h |   3 +-
 .../Component/RecycleList/WXCellSlotComponent.m |   7 +-
 .../RecycleList/WXComponent+DataBinding.h       |   2 +-
 .../RecycleList/WXComponent+DataBinding.mm      |  89 ++++++-
 .../Component/RecycleList/WXJSASTParser.mm      |   3 +-
 .../RecycleList/WXRecycleListComponent.h        |  11 +-
 .../RecycleList/WXRecycleListComponent.m        | 236 ++++++++++++++-----
 .../RecycleList/WXRecycleListDataManager.h      |  11 +
 .../RecycleList/WXRecycleListDataManager.m      |  56 +++++
 .../RecycleList/WXRecycleListTemplateManager.h  |   2 +
 .../RecycleList/WXRecycleListTemplateManager.m  |  14 +-
 .../RecycleList/WXRecycleListUpdateManager.m    |   5 -
 .../Component/Recycler/WXRecyclerComponent.m    |   1 -
 .../Sources/Component/WXComponent_internal.h    |   2 +
 .../WeexSDK/Sources/Events/WXComponent+Events.m |  25 ++
 .../WeexSDK/Sources/Manager/WXBridgeManager.h   |   9 +
 .../WeexSDK/Sources/Manager/WXBridgeManager.m   |  14 ++
 .../Sources/Manager/WXComponentManager.m        |   4 +-
 ios/sdk/WeexSDK/Sources/Model/WXComponent.m     |   3 +
 ios/sdk/WeexSDK/Sources/Module/WXDomModule.m    |  16 ++
 .../Sources/View/WXComponent+ViewManagement.m   |   4 +
 24 files changed, 468 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/playground/WeexDemo/Info.plist
----------------------------------------------------------------------
diff --git a/ios/playground/WeexDemo/Info.plist 
b/ios/playground/WeexDemo/Info.plist
index 6fd3e06..5ee55ec 100644
--- a/ios/playground/WeexDemo/Info.plist
+++ b/ios/playground/WeexDemo/Info.plist
@@ -26,7 +26,7 @@
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
-       <string>2.0</string>
+       <string>2.2</string>
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleURLTypes</key>
@@ -39,7 +39,7 @@
                </dict>
        </array>
        <key>CFBundleVersion</key>
-       <string>2</string>
+       <string>3</string>
        <key>LSRequiresIPhoneOS</key>
        <true/>
        <key>NSAppTransportSecurity</key>

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h 
b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
index 8ef129f..b3b66b6 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.h
@@ -18,6 +18,7 @@
  */
 
 #import <Foundation/Foundation.h>
+#import <JavaScriptCore/JavaScriptCore.h>
 
 @class WXCallJSMethod;
 @class WXSDKInstance;
@@ -122,4 +123,6 @@
  **/
 - (void)resetEnvironment;
 
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args 
onContext:(JSContext*)context completion:(void (^)(JSValue * value))complection;
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m 
b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index 5af88a0..af473cf 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -557,6 +557,33 @@ _Pragma("clang diagnostic pop") \
     [self performSelector:@selector(_sendQueueLoop) withObject:nil];
 }
 
+- (void)callJSMethod:(NSString *)method args:(NSArray *)args 
onContext:(JSContext*)context completion:(void (^)(JSValue * value))complection
+{
+    NSMutableArray *newArg = nil;
+    if (!context) {
+        if ([self.jsBridge isKindOfClass:[WXJSCoreBridge class]]) {
+           context = [(NSObject*)_jsBridge valueForKey:@"jsContext"];
+        }
+    }
+    if (self.frameworkLoadFinished) {
+        newArg = [args mutableCopy];
+        if ([newArg containsObject:complection]) {
+            [newArg removeObject:complection];
+        }
+        WXLogDebug(@"Calling JS... method:%@, args:%@", method, args);
+        JSValue *value = [[context globalObject] invokeMethod:method 
withArguments:args];
+        if (complection) {
+            complection(value);
+        }
+    } else {
+        newArg = [args mutableCopy];
+        if (complection) {
+            [newArg addObject:complection];
+        }
+        [_methodQueue addObject:@{@"method":method, @"args":[newArg copy]}];
+    }
+}
+
 - (void)executeAllJsService
 {
     for(NSDictionary *service in _jsServiceQueue) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.h
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.h 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.h
index 4e62676..e3721be 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.h
@@ -20,9 +20,10 @@
 #import <Foundation/Foundation.h>
 #import "WXComponent.h"
 
+static const NSString *WXDefaultRecycleTemplateType = @"default";
 @interface WXCellSlotComponent : WXComponent
 
-@property (nonatomic, strong) NSString *templateType;
+@property (nonatomic, strong) NSString *templateCaseType;
 
 - (void)updateCellData:(NSDictionary *)data;
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
index 0cbd97b..a6adec0 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXCellSlotComponent.m
@@ -25,8 +25,6 @@
 #import "WXAssert.h"
 #import "WXScrollerComponent.h"
 
-static const NSString *WXDefaultRecycleTemplateType = 
@"WXDefaultRecycleTemplateType";
-
 @implementation WXCellSlotComponent
 
 - (instancetype)initWithRef:(NSString *)ref
@@ -39,7 +37,10 @@ static const NSString *WXDefaultRecycleTemplateType = 
@"WXDefaultRecycleTemplate
     self = [super initWithRef:ref type:type styles:styles 
attributes:attributes events:events weexInstance:weexInstance];
     if (self) {
         // TODO: isRecycle / insertAnimation / deleteAnimation / 
keepScrollPosition
-        _templateType = attributes[@"templateType"] ? [WXConvert 
NSString:attributes[@"templateType"]] : WXDefaultRecycleTemplateType;
+        if (attributes[@"default"]) {
+            _templateCaseType = @"default";
+        }
+        _templateCaseType = attributes[@"case"] ? [WXConvert 
NSString:attributes[@"case"]] : WXDefaultRecycleTemplateType;
         _lazyCreateView = YES;
         _isNeedJoinLayoutSystem = NO;
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.h
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.h 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.h
index 971252a..b68b159 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.h
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.h
@@ -22,10 +22,10 @@
 static const NSString *WXBindingIdentify = @"@binding";
 static const NSString *WXBindingMatchIdentify = @"[[match]]";
 static const NSString *WXBindingRepeatIdentify = @"[[repeat]]";
+static const NSString *WXBindingOnceIdentify = @"[[once]]";
 static const NSString *WXBindingRepeatExprIdentify = @"@expression";
 static const NSString *WXBindingRepeatIndexIdentify = @"@index";
 static const NSString *WXBindingRepeatLabelIdentify = @"@alias";
 
 @interface WXComponent (DataBinding)
-
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.mm
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.mm 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.mm
index aad49da..aeb6a36 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXComponent+DataBinding.mm
@@ -21,8 +21,13 @@
 #import "WXComponent_internal.h"
 #import "WXSDKInstance_private.h"
 #import "WXComponentManager.h"
+#import "WXSDKManager.h"
 #import "WXAssert.h"
 #import "WXJSASTParser.h"
+#import "WXBridgeManager.h"
+#import "WXUtility.h"
+#import "WXRecycleListComponent.h"
+#import "WXRecycleListDataManager.h"
 
 #import <JavaScriptCore/JavaScriptCore.h>
 
@@ -43,7 +48,30 @@ static JSContext *jsContext;
 - (void)updateBindingData:(NSDictionary *)data
 {
     WXAssertComponentThread();
+    NSString * listRef = nil;
+    NSIndexPath *indexPath  = nil;
+    NSDictionary * dictionary = nil;
+    listRef = data[@"recycleListComponentRef"];
+    indexPath = data[@"indexPath"];
+    NSString *phase = data[@"@phase"];
+    if (!indexPath || !listRef) {
+        if (data[@"aliasKey"]) {
+            id key = data[@"aliasKey"];
+            dictionary =  data[key];
+        } else {
+            dictionary = data;
+        }
+        listRef = dictionary[@"recycleListComponentRef"];
+        indexPath = dictionary[@"indexPath"];
+    }
+    if (!phase && dictionary) {
+        phase = dictionary[@"@phase"];
+    }
     
+    if (!indexPath || !listRef) {
+        return;
+    }
+    WXRecycleListComponent * recycleListComponent = 
(WXRecycleListComponent*)[self.weexInstance.componentManager 
componentForRef:listRef];
     if (_isSkipUpdate) {
         _isSkipUpdate = NO;
         return;
@@ -62,7 +90,7 @@ static JSContext *jsContext;
     }
     
     if (templateComponent->_bindingProps) {
-        NSMutableDictionary *newData = [NSMutableDictionary dictionary];
+        __block NSMutableDictionary *newData = [NSMutableDictionary 
dictionary];
         [templateComponent->_bindingProps 
enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, WXDataBindingBlock 
 _Nonnull block, BOOL * _Nonnull stop) {
             BOOL needUpdate;
             id value = block(data, &needUpdate);
@@ -71,9 +99,43 @@ static JSContext *jsContext;
             }
         }];
         
+        if (self.attributes[@"@isComponentRoot"]) {
+            if (![recycleListComponent.dataManager 
virtualComponentDataWithIndexPath:indexPath]) {
+                static NSUInteger __componentId = 0;
+                self->_virtualComponentId = [NSString 
stringWithFormat:@"%@@%ld", listRef, __componentId % (2048*1024)];
+                __componentId++;
+                dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
+                [[WXSDKManager bridgeMgr] 
callComponentHook:self.weexInstance.instanceId 
componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"create" 
args:@[self->_virtualComponentId, newData] competion:^(JSValue *value) {
+                    [newData addEntriesFromDictionary:[value 
toDictionary][@"0"]];
+                    [newData setObject:indexPath forKey:@"indexPath"];
+                    [newData setObject:listRef 
forKey:@"recycleListComponentRef"];
+                    [[recycleListComponent dataManager] 
updateVirtualComponentData:self->_virtualComponentId data:newData];
+                    dispatch_semaphore_signal(semaphore);
+                }];
+                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
+                
+                [[WXSDKManager bridgeMgr] 
callComponentHook:self.weexInstance.instanceId 
componentId:self->_virtualComponentId type:@"lifecycle" hook:@"attach" args:nil 
competion:nil];
+                if ([newData count]) {
+                    data = newData;
+                }
+            } else {
+                newData[@"componentDataId"] = self->_virtualComponentId;
+                NSDictionary * virtualComponentData = 
[recycleListComponent.dataManager virtualComponentDataWithIndexPath:indexPath];
+                [newData addEntriesFromDictionary:virtualComponentData];
+                [newData addEntriesFromDictionary:data];
+                data = newData;
+            }
+        }
+    }
+    if (phase) {
+        NSMutableDictionary * newData = [data mutableCopy];
+        newData[@"@phase"] = phase;
         data = newData;
     }
-    
+    if (self->_templateComponent && self->_templateComponent->_dataBindOnce && 
recycleListComponent && data[@"@phase"]) {
+        WXLogInfo(@"interrupt update data: %@ because of v-once ", data);
+        return;
+    }
     if (!_isRepeating) {
         WXDataBindingBlock repeatBlock = templateComponent->_bindingRepeat;
         if (repeatBlock) {
@@ -126,12 +188,16 @@ static JSContext *jsContext;
                 [self.weexInstance.componentManager 
updateAttributes:newAttributesOrStyles forComponent:self.ref];
             } else if (i == WXDataBindingTypeEvents) {
                 [self _addEventParams:newAttributesOrStyles];
+            } else if (i == WXDataBindingTypeProp) {
             }
         }
     }
     
     NSArray *subcomponents = self.subcomponents;
     for (WXComponent *subcomponent in subcomponents) {
+        if (subcomponent->_virtualComponentId &&dictionary[@"componentDataId"] 
&& ![subcomponent->_virtualComponentId 
isEqualToString:dictionary[@"componentDataId"]]) {
+            continue;
+        }
         [subcomponent updateBindingData:data];
     }
 }
@@ -289,7 +355,9 @@ static JSContext *jsContext;
         }
         
         if (type == WXDataBindingTypeAttributes) {
-            if ([WXBindingMatchIdentify isEqualToString:name]) {
+            if ([WXBindingOnceIdentify isEqualToString:name]) {
+                _dataBindOnce = [WXConvert BOOL:binding];
+            } else if ([WXBindingMatchIdentify isEqualToString:name]) {
                 WXJSASTParser *parser = [WXJSASTParser 
parserWithScript:binding];
                 WXJSExpression *expression = [parser parseExpression];
                 _bindingMatch = [self bindingBlockWithExpression:expression];
@@ -323,7 +391,7 @@ static JSContext *jsContext;
             *needUpdate = NO;
             return nil;
         } else if (expression->is<WXJSIdentifier>()) {
-            NSString *identiferName = [NSString 
stringWithCString:(((WXJSIdentifier *)expression)->name).c_str() 
encoding:[NSString defaultCStringEncoding]];
+            NSString *identiferName = [NSString 
stringWithCString:const_cast<char*>((((WXJSIdentifier 
*)expression)->name).c_str()) encoding:NSUTF8StringEncoding];
             if (data[identiferName]) {
                 *needUpdate = YES;
                 return data[identiferName];
@@ -344,9 +412,16 @@ static JSContext *jsContext;
                     return [object objectAtIndex:[propertyName 
unsignedIntegerValue]];
                 }
             } else {
-                NSString *propertyName = [NSString 
stringWithCString:(((WXJSStringLiteral *)member->property)->value).c_str() 
encoding:[NSString defaultCStringEncoding]];
-                *needUpdate = objectNeedUpdate;
-                return object[propertyName];
+                WXJSExpression * memberExpression = member->property;
+                if (memberExpression->is<WXJSIdentifier>()) {
+                    NSString *propertyName = [NSString 
stringWithCString:(((WXJSStringLiteral *)member->property)->value).c_str() 
encoding:[NSString defaultCStringEncoding]];
+                    *needUpdate = objectNeedUpdate;
+                    return object[propertyName];
+                } else {
+                    id retvalue = [self 
bindingBlockWithExpression:member->property](object, &objectNeedUpdate);
+                    *needUpdate = objectNeedUpdate || propertyNeedUpdate;
+                    return retvalue;
+                }
             }
             
             return nil;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
index 7e7a565..0be6647 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXJSASTParser.mm
@@ -826,10 +826,9 @@ static int binaryPrecedence(WXJSToken *token)
 - (WXJSExpression *)parseMemberExpression
 {
     WXJSExpression *expr = [self parsePrimaryExpression];
-    
     if ([self match:"."]) {
         [self expect:"."];
-        WXJSExpression *property = [self parsePrimaryExpression];
+        WXJSExpression * property = [self parseMemberExpression];
         WXJSMemberExpression *memberExpr = new WXJSMemberExpression();
         memberExpr->object = expr;
         memberExpr->property = property;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.h
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.h 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.h
index a072752..e4be617 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.h
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.h
@@ -20,6 +20,15 @@
 #import <Foundation/Foundation.h>
 #import "WXScrollerComponent.h"
 
-@interface WXRecycleListComponent : WXScrollerComponent 
+@class WXRecycleListDataManager;
+@class WXRecycleListTemplateManager;
+@class WXRecycleListUpdateManager;
+
+@interface WXRecycleListComponent : WXScrollerComponent
+
+@property(nonatomic, strong) WXRecycleListDataManager *dataManager;
+@property(nonatomic, strong) WXRecycleListTemplateManager *templateManager;
+@property(nonatomic, strong) WXRecycleListUpdateManager *updateManager;
+
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
index 71a52f5..03f233a 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListComponent.m
@@ -29,6 +29,9 @@
 #import "WXRecycleListDataManager.h"
 #import "WXRecycleListTemplateManager.h"
 #import "WXRecycleListUpdateManager.h"
+#import "WXBridgeManager.h"
+#import "WXSDKManager.h"
+#import "WXComponent+DataBinding.h"
 
 @interface WXRecycleListComponent () <WXRecycleListLayoutDelegate, 
WXRecycleListUpdateDelegate, UICollectionViewDelegateFlowLayout, 
UICollectionViewDataSource>
 
@@ -36,11 +39,7 @@
 
 @implementation WXRecycleListComponent
 {
-    WXRecycleListDataManager *_dataManager;
-    WXRecycleListTemplateManager *_templateManager;
-    WXRecycleListUpdateManager *_updateManager;
-    
-    NSString *_templateKey;
+    NSString *_templateSwitchKey;
     NSString *_aliasKey;
     NSString *_indexKey;
     __weak UICollectionView *_collectionView;
@@ -52,11 +51,14 @@
 }
 
 WX_EXPORT_METHOD(@selector(appendData:))
-WX_EXPORT_METHOD(@selector(insertData:atIndex:))
-WX_EXPORT_METHOD(@selector(updateData:atIndex:))
-WX_EXPORT_METHOD(@selector(removeData:))
+WX_EXPORT_METHOD(@selector(appendRange:))
+WX_EXPORT_METHOD(@selector(insertData:data:))
+WX_EXPORT_METHOD(@selector(updateData:data:))
+WX_EXPORT_METHOD(@selector(removeData:count:))
 WX_EXPORT_METHOD(@selector(moveData:toIndex:))
 WX_EXPORT_METHOD(@selector(scrollTo:options:))
+WX_EXPORT_METHOD(@selector(insertRange:range:))
+WX_EXPORT_METHOD(@selector(setListData:))
 
 - (instancetype)initWithRef:(NSString *)ref
                        type:(NSString *)type
@@ -66,11 +68,11 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
                weexInstance:(WXSDKInstance *)weexInstance
 {
     if (self = [super initWithRef:ref type:type styles:styles 
attributes:attributes events:events weexInstance:weexInstance]) {
-        _dataManager = [[WXRecycleListDataManager alloc] 
initWithData:attributes[@"listData"]];
+        _dataManager = attributes[@"listData"]? [[WXRecycleListDataManager 
alloc] initWithData:attributes[@"listData"]] : [WXRecycleListDataManager new];
         _templateManager = [WXRecycleListTemplateManager new];
         _updateManager = [WXRecycleListUpdateManager new];
         _updateManager.delegate = self;
-        _templateKey = [WXConvert NSString:attributes[@"templateKey"]] ? : 
@"templateType";
+        _templateSwitchKey = [WXConvert NSString:attributes[@"switch"]];
         _aliasKey = [WXConvert NSString:attributes[@"alias"]];
         _indexKey = [WXConvert NSString:attributes[@"index"]];
         _sizeCache = [NSMutableDictionary dictionary];
@@ -120,6 +122,15 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
         NSArray *listData = attributes[@"listData"];
         [self _updateListData:listData withCompletion:nil animation:NO];
     }
+    if (attributes[@"switch"]) {
+        _templateSwitchKey = [WXConvert NSString:attributes[@"switch"]];
+    }
+    if (attributes[@"alias"]) {
+        _aliasKey = [WXConvert NSString:attributes[@"alias"]];
+    }
+    if (attributes[@"index"]) {
+        _indexKey = [WXConvert NSString:attributes[@"index"]];
+    }
 }
 
 - (CGPoint)absolutePositionForComponent:(WXComponent *)component
@@ -179,18 +190,33 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
 
 #pragma mark - Exported Component Methods
 
-- (void)appendData:(NSArray *)appendingData
+- (void)appendData:(id)appendingData
 {
-    if (![appendingData isKindOfClass:[NSArray class]]) {
-        WXLogError(@"wrong format of appending data:%@", appendingData);
+    if (!appendingData){
+        return;
+    }
+    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
+    [newListData addObject:appendingData];
+}
+
+- (void)appendRange:(NSArray*)data
+{
+    if (![data isKindOfClass:[NSArray class]]) {
+        WXLogError(@"wrong format of appending data:%@", data);
         return;
     }
     
     NSArray *oldData = [_dataManager data];
-    [_updateManager updateWithAppendingData:appendingData oldData:oldData 
completion:nil animation:NO];
+    [_updateManager updateWithAppendingData:data oldData:oldData 
completion:nil animation:NO];
 }
 
-- (void)insertData:(id)data atIndex:(NSUInteger)index
+- (void)setListData:(NSArray*)data
+{
+    if ([data count]) {
+        [_dataManager updateData:data];
+    }
+}
+- (void)insertData:(NSUInteger)index data:(id)data
 {
     // TODO: bring the update logic to UpdateManager
     // TODO: update cell because index has changed
@@ -202,47 +228,110 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
         NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index 
inSection:0];
         
         [UIView performWithoutAnimation:^{
-            [_collectionView insertItemsAtIndexPaths:@[indexPath]];
+            [self->_collectionView insertItemsAtIndexPaths:@[indexPath]];
         }];
     }
 }
 
-- (void)updateData:(id)data atIndex:(NSUInteger)index
+- (void)updateComponentData:(NSString*)componentDataId 
componentData:(NSDictionary*)componentData callback:(NSString*)callbackId
 {
-    // TODO: bring the update logic to UpdateManager
-    NSMutableArray *newListData = [[_dataManager data] mutableCopy];
-    if (index < newListData.count) {
-        newListData[index] = data;
-        [_dataManager updateData:newListData];
-        
-        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:index 
inSection:0];
-        UICollectionViewCell *cellView = [_collectionView 
cellForItemAtIndexPath:indexPath];
-        WXCellSlotComponent *cellComponent = (WXCellSlotComponent 
*)cellView.wx_component;
-        if (cellComponent) {
-            [self _updateBindingData:data forCell:cellComponent 
atIndexPath:indexPath];
+    NSMutableDictionary * virtualComponentData = [[_dataManager 
virtualComponentDataWithId:componentDataId] mutableCopy];
+    NSIndexPath * indexPath = virtualComponentData[@"indexPath"];
+    if (!indexPath) {
+        return;
+    }
+    virtualComponentData = virtualComponentData?:[NSMutableDictionary new];
+    [virtualComponentData addEntriesFromDictionary:componentData];
+    [_dataManager updateVirtualComponentData:componentDataId 
data:[virtualComponentData copy]];
+    virtualComponentData[@"@phase"] = @"update";
+    virtualComponentData[@"callbackId"] = callbackId;
+    [self _updateDataForCellSlotAtIndexPath:indexPath 
data:virtualComponentData];
+}
+
+- (void)_updateDataForCellSlotAtIndexPath:(NSIndexPath*)indexPath 
data:(NSDictionary*)data
+{
+    if(!indexPath || !data) {
+        return;
+    }
+    WXPerformBlockOnMainThread(^{
+        UICollectionViewCell * cellView = [self->_collectionView 
cellForItemAtIndexPath:indexPath];
+        WXCellSlotComponent * cellSlotComponent = 
(WXCellSlotComponent*)cellView.wx_component;
+        if (cellSlotComponent) {
+            [self _updateBindingData:data forCell:cellSlotComponent 
atIndexPath:indexPath];
         }
+        // callback when update virtual component data success.
+        NSString * callbackId = data[@"callbackId"];
+        if (callbackId) {
+            [[WXSDKManager bridgeMgr] callBack:self.weexInstance.instanceId 
funcId:callbackId params:@{@"result":@"success"}];
+        }
+    });
+}
+
+- (void)updateData:(NSUInteger)index data:(id)data
+{
+    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
+    if (!data && index > [newListData count]) {
+        return;
+    }
+    NSIndexPath * indexPath = [NSIndexPath indexPathForRow:index inSection:0];
+    NSDictionary * virtualComponentData = [_dataManager 
virtualComponentDataWithIndexPath:indexPath];
+    if ([virtualComponentData[WXBindingOnceIdentify] boolValue]) {
+        return;
+    }
+    
+    // TODO: bring the update logic to UpdateManager
+    newListData[index] = data;
+    [_dataManager updateData:newListData];
+    NSString* virtualComponentId = [_dataManager 
virtualComponentIdWithIndexPath:indexPath];
+    [_dataManager updateVirtualComponentData:virtualComponentId data:data];
+    NSMutableDictionary * newData = nil;
+    if (![data isKindOfClass:[NSDictionary class]]) {
+         newData = [NSMutableDictionary new];
+        [newData setObject:@"data" forKey:data];
+        data = newData;
+    }
+    newData = [data mutableCopy];
+    newData[@"@phase"] = @"update";
+    [self _updateDataForCellSlotAtIndexPath:indexPath data:[newData copy]];
+}
+
+- (void)insertRange:(NSInteger)index range:(NSArray*)data
+{
+    if (![data count]) {
+        WXLogDebug(@"ignore invalid insertRange");
+        return;
     }
+    
+    NSMutableArray * newListData = [[_dataManager data] mutableCopy];
+    NSRange range = NSMakeRange(index,[data count]);
+    NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
+    [newListData insertObjects:data atIndexes:indexSet];
+    [_dataManager updateData:newListData];
+    [_collectionView reloadData];
 }
 
-- (void)removeData:(NSArray *)indexes
+- (void)removeData:(NSInteger)index count:(NSInteger)count
 {
     // TODO: bring the update logic to UpdateManager
+    
     NSMutableArray *newListData = [[_dataManager data] mutableCopy];
-    NSMutableIndexSet *indexSet = [NSMutableIndexSet new];
-    NSMutableArray *indexPaths = [NSMutableArray array];
-    for (NSNumber *index in indexes) {
-        if ([index unsignedIntegerValue] >= newListData.count) {
-            WXLogError(@"invalid remove index:%@", index);
-            continue;
-        }
-        [indexSet addIndex:[index unsignedIntegerValue]];
-        [indexPaths addObject:[NSIndexPath indexPathForItem:[index 
unsignedIntegerValue] inSection:0]];
+    if (index > [newListData count] || index + count - 1 > [newListData 
count]) {
+        
+        return;
     }
-    
+    NSIndexSet *indexSet = [NSIndexSet 
indexSetWithIndexesInRange:NSMakeRange(index, count)];
     [newListData removeObjectsAtIndexes:indexSet];
+    __block NSMutableArray<NSIndexPath*>* indexPaths = [NSMutableArray new];
+    [indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull 
stop) {
+        NSIndexPath* indexPath = [NSIndexPath indexPathForRow:idx inSection:0];
+        [indexPaths addObject:indexPath];
+    }];
+    
     [_dataManager updateData:newListData];
+    [_dataManager deleteVirtualComponentAtIndexPaths:indexPaths];
     [UIView performWithoutAnimation:^{
-        [_collectionView deleteItemsAtIndexPaths:indexPaths];
+        [self->_collectionView deleteItemsAtIndexPaths:indexPaths];
+        [self->_collectionView reloadSections:[NSIndexSet 
indexSetWithIndex:0]];
     }];
 }
 
@@ -258,7 +347,7 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
     NSIndexPath *fromIndexPath = [NSIndexPath indexPathForItem:fromIndex 
inSection:0];
     NSIndexPath *toIndexPath = [NSIndexPath indexPathForItem:toIndex 
inSection:0];
     [UIView performWithoutAnimation:^{
-        [_collectionView moveItemAtIndexPath:fromIndexPath 
toIndexPath:toIndexPath];
+        [self->_collectionView moveItemAtIndexPath:fromIndexPath 
toIndexPath:toIndexPath];
     }];
 }
 
@@ -287,11 +376,30 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
 
 #pragma mark - Private
 
-- (void)_updateBindingData:(NSDictionary *)data forCell:(WXCellSlotComponent 
*)cellComponent atIndexPath:(NSIndexPath *)indexPath
+- (void)_updateBindingData:(id)data forCell:(WXCellSlotComponent 
*)cellComponent atIndexPath:(NSIndexPath *)indexPath
 {
-    if (_aliasKey) {
-        data = @{_aliasKey:data};
+    id originalData = data;
+    if (![originalData isKindOfClass:[NSDictionary class]]) {
+        if (_aliasKey) {
+            NSMutableDictionary * dictionary = [NSMutableDictionary 
dictionary];
+            [dictionary setObject:data forKey:_aliasKey];
+            data = dictionary;
+        } else {
+            return;
+        }
+    }
+    
+    if (!data[@"indexPath"] || !data[@"recycleListComponentRef"]) {
+        NSMutableDictionary * dataNew = [data mutableCopy];
+        dataNew[@"recycleListComponentRef"] = self.ref;
+        dataNew[@"indexPath"] = indexPath;
+        data = dataNew;
     }
+    
+    if ([originalData isKindOfClass:[NSDictionary class]] && _aliasKey 
&&!data[@"phase"]) {
+        data = @{_aliasKey:data,@"aliasKey":_aliasKey};
+    }
+    
     if (_indexKey) {
         NSMutableDictionary *dataNew = [data mutableCopy];
         dataNew[_indexKey] = @(indexPath.item);
@@ -301,8 +409,9 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
 #ifdef DEBUG
     NSDate *startTime = [NSDate date];
 #endif
+    
     WXPerformBlockSyncOnComponentThread(^{
-        [cellComponent updateCellData:data];
+        [cellComponent updateCellData:[data copy]];
     });
 #ifdef DEBUG
     double duration = -[startTime timeIntervalSinceNow] * 1000;
@@ -350,16 +459,13 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
cellForItemAtIndexPath:(NSIndexPath *)indexPath
 {
     // 1. get the data relating to the cell
-    NSDictionary *data = [_dataManager dataAtIndex:indexPath.row];
-    if (!data || ![data isKindOfClass:[NSDictionary class]]) {
-        WXLogError(@"No data or wrong data format for index:%zd, data:%@", 
indexPath.item, data);
-        return nil;
-    }
+    id data = [_dataManager dataAtIndex:indexPath.row];
     
     // 2. get the template type specified by data
-    NSString *templateType = data[_templateKey];
+    NSString * templateType = [self templateType:indexPath];
+    _templateManager.collectionView = collectionView;
     if (!templateType) {
-        WXLogError(@"Each data should have a value for %@ to indicate template 
type", _templateKey);
+        WXLogError(@"Each data should have a value for %@ to indicate template 
type", _templateSwitchKey);
         return nil;
     }
     
@@ -392,9 +498,7 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
     
     WXLogDebug(@"Return cell view:%@, indexPath:%@", cellView, indexPath);
     
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [self handleAppear];
-    });
+    [self handleAppear];
     
     return cellView;
 }
@@ -424,8 +528,8 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
     if (size) {
         return [size CGSizeValue];
     } else {
-        NSDictionary *data = [_dataManager dataAtIndex:indexPath.row];
-        WXCellSlotComponent *cell = [_templateManager 
templateWithType:data[_templateKey]];
+
+        WXCellSlotComponent *cell = [_templateManager templateWithType:[self 
templateType:indexPath]];
         CGSize size = cell.calculatedFrame.size;
         _sizeCache[indexPath] = [NSValue valueWithCGSize:size];
         return CGSizeMake(_collectionView.frame.size.width, size.height);
@@ -456,4 +560,22 @@ WX_EXPORT_METHOD(@selector(scrollTo:options:))
     
 }
 
+- (NSString*)templateType:(NSIndexPath*)indexPath
+{
+    NSDictionary *data = [_dataManager dataAtIndex:indexPath.row];
+    // default is first template.
+    NSString *templateType = [_templateManager topTemplate].templateCaseType;
+    if (!data || ![data isKindOfClass:[NSDictionary class]]) {
+        return templateType;
+    }
+    
+    if (_templateSwitchKey &&data[_templateSwitchKey]){
+        templateType = data[_templateSwitchKey];
+    } else if (data[WXDefaultRecycleTemplateType]){
+        // read the default type.
+        templateType = data[WXDefaultRecycleTemplateType];
+    }
+    return templateType;
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.h
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.h 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.h
index fc053c5..0a5641e 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.h
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.h
@@ -31,4 +31,15 @@
 
 - (NSInteger)numberOfItems;
 
+- (NSInteger)numberOfVirtualComponent;
+
+- (NSDictionary*)virtualComponentDataWithId:(NSString*)componentId;
+
+- (void)updateVirtualComponentData:(NSString*)componentId 
data:(NSDictionary*)data;
+
+- (NSDictionary*)virtualComponentDataWithIndexPath:(NSIndexPath*)indexPath;
+
+- (NSString*)virtualComponentIdWithIndexPath:(NSIndexPath*)indexPath;
+
+- (void)deleteVirtualComponentAtIndexPaths:(NSArray<NSIndexPath*>*)indexPaths;
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.m
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.m 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.m
index 8d27171..5f6f1fc 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.m
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListDataManager.m
@@ -25,6 +25,17 @@
 @implementation WXRecycleListDataManager
 {
     NSArray *_data;
+    NSMapTable<NSString*, NSDictionary*>* _virtualComponentData;
+    NSMapTable<NSIndexPath*, NSString*>*  _renderStatus;
+}
+
+- (instancetype)init
+{
+    if (self = [super init]) {
+        _virtualComponentData = [NSMapTable strongToStrongObjectsMapTable];
+        _renderStatus = [NSMapTable strongToStrongObjectsMapTable];
+    }
+    return self;
 }
 
 - (instancetype)initWithData:(NSArray *)data
@@ -68,4 +79,49 @@
     return [_data count];
 }
 
+- (void)updateVirtualComponentData:(NSString*)componentId 
data:(NSDictionary*)data
+{
+    if (!componentId) {
+        return;
+    }
+    NSIndexPath * indexPath = [data objectForKey:@"indexPath"];
+    [_virtualComponentData setObject:data forKey:componentId];
+    [_renderStatus setObject:componentId forKey:indexPath];
+    
+//    NSMutableDictionary* newComponentData = [[_virtualComponentData 
objectForKey:componentId] mutableCopy];
+//    if (newComponentData) {
+//        [newComponentData addEntriesFromDictionary:data];
+//    } else {
+//        newComponentData = [data mutableCopy];
+//    }
+}
+
+- (void)deleteVirtualComponentAtIndexPaths:(NSArray<NSIndexPath*>*)indexPaths
+{
+    [_virtualComponentData removeAllObjects];
+    [_renderStatus removeAllObjects];
+}
+
+- (NSDictionary*)virtualComponentDataWithId:(NSString*)componentId
+{
+    return [_virtualComponentData objectForKey:componentId];
+}
+
+- (NSString*)virtualComponentIdWithIndexPath:(NSIndexPath*)indexPath
+{
+    return [_renderStatus objectForKey:indexPath];
+}
+
+- (NSDictionary*)virtualComponentDataWithIndexPath:(NSIndexPath*)indexPath
+{
+    NSString * componentDataId = [self 
virtualComponentIdWithIndexPath:indexPath];
+    
+    return [self virtualComponentDataWithId:componentDataId];
+}
+
+- (NSInteger)numberOfVirtualComponent
+{
+    return [_virtualComponentData count];
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.h
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.h 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.h
index 389dbb8..926c2f1 100644
--- 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.h
+++ 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.h
@@ -30,4 +30,6 @@
 
 - (WXCellSlotComponent *)templateWithType:(NSString *)type;
 
+- (WXCellSlotComponent *)topTemplate;
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.m
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.m 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.m
index 87ecd90..199d551 100644
--- 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.m
+++ 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListTemplateManager.m
@@ -62,7 +62,7 @@
 {
     WXAssertMainThread();
     
-    NSString *templateType = component.templateType;
+    NSString *templateType = component.templateCaseType;
     WXAssert(templateType != nil, @"cell-slot:%@ must have a template id!", 
component);
     
     [_templateTypeMap setObject:component forKey:templateType];
@@ -91,4 +91,16 @@
     [_collectionView registerClass:[WXReusableCollectionViewCell class] 
forCellWithReuseIdentifier:templateID];
 }
 
+- (WXCellSlotComponent *)topTemplate
+{
+    WXCellSlotComponent * cellTemplate = nil;
+    for (NSString *templateType in [_templateTypeMap.keyEnumerator.allObjects 
copy]) {
+        cellTemplate = [self templateWithType:templateType];
+        if (!cellTemplate) {
+            break;
+        }
+    }
+    return cellTemplate;
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListUpdateManager.m
----------------------------------------------------------------------
diff --git 
a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListUpdateManager.m 
b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListUpdateManager.m
index cdeae05..d500895 100644
--- a/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListUpdateManager.m
+++ b/ios/sdk/WeexSDK/Sources/Component/RecycleList/WXRecycleListUpdateManager.m
@@ -208,11 +208,6 @@
     NSMutableSet<NSIndexPath *> *deleteIndexPaths = [NSMutableSet set];
     NSMutableSet<NSIndexPath *> *insertIndexPaths = [NSMutableSet set];
     
-    for (WXDiffUpdateIndex *update in diffResult.updates) {
-        NSIndexPath *reloadIndexPath = [NSIndexPath 
indexPathForItem:update.oldIndex inSection:0];
-        [reloadIndexPaths addObject:reloadIndexPath];
-    }
-    
     [diffResult.updates enumerateObjectsUsingBlock:^(WXDiffUpdateIndex * 
_Nonnull update, NSUInteger idx, BOOL * _Nonnull stop) {
         NSIndexPath *reloadIndexPath = [NSIndexPath 
indexPathForItem:update.oldIndex inSection:0];
         [reloadIndexPaths addObject:reloadIndexPath];

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m 
b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
index be4d7a6..aa4bf1a 100644
--- a/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/Recycler/WXRecyclerComponent.m
@@ -124,7 +124,6 @@ typedef enum : NSUInteger {
     if (self = [super initWithRef:ref type:type styles:styles 
attributes:attributes events:events weexInstance:weexInstance]) {
         [self _fillPadding];
         
-        
         if ([type isEqualToString:@"waterfall"] || (attributes[@"layout"] && 
[attributes[@"layout"] isEqualToString:@"multi-column"])) {
             // TODO: abstraction
             _layoutType = WXRecyclerLayoutTypeMultiColumn;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h 
b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
index eddbfe7..c8c7b5b 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
@@ -146,8 +146,10 @@ typedef id (^WXDataBindingBlock)(NSDictionary *data, BOOL 
*needUpdate);
     WXDataBindingBlock _bindingRepeat;
     NSString *_repeatIndexIdentify;
     NSString *_repeatLabelIdentify;
+    NSString *_virtualComponentId;// for recycleList subcomponent
     BOOL _isRepeating;
     BOOL _isSkipUpdate;
+    BOOL _dataBindOnce;
     
     NSMutableDictionary<NSString *, WXDataBindingBlock> *_bindingProps;
     NSMutableDictionary<NSString *, WXDataBindingBlock> *_bindingAttributes;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m 
b/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
index 5747fe4..621df21 100644
--- a/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
+++ b/ios/sdk/WeexSDK/Sources/Events/WXComponent+Events.m
@@ -26,6 +26,10 @@
 #import "WXUtility.h"
 #import "WXSDKManager.h"
 #import "WXSDKInstance_private.h"
+#import "WXDefine.h"
+#import "WXRecycleListComponent.h"
+#import "WXRecycleListDataManager.h"
+
 #import <objc/runtime.h>
 #import <UIKit/UIGestureRecognizerSubclass.h>
 #import "WXComponent+PseudoClassManagement.h"
@@ -108,6 +112,15 @@
     if (params) {
         [dict addEntriesFromDictionary:params];
     }
+    WXRecycleListComponent * recyleListComponent  = 
(WXRecycleListComponent*)[self getRecycleListComponent];
+    if (recyleListComponent) {
+        NSIndexPath * indexPath = 
[((UICollectionView*)recyleListComponent.view) 
indexPathForItemAtPoint:[self.view.superview
+                                                                               
                           convertPoint:self.view.center 
toView:recyleListComponent.view]];
+        NSString * virtualComponentId = [recyleListComponent.dataManager 
virtualComponentIdWithIndexPath:indexPath];
+        if (virtualComponentId) {
+            dict[@"componentId"] = virtualComponentId;
+        }
+    }
     
     NSArray *handlerArguments = [self _paramsForEvent:eventName];
     NSString *ref = _templateComponent ? _templateComponent.ref  : self.ref;
@@ -714,6 +727,18 @@ if ([removeEventName isEqualToString:@#eventName]) {\
     return resultTouch;
 }
 
+// find virtual component's root component
+- (WXComponent*)getRecycleListComponent
+{
+    if ([self isKindOfClass:[WXRecycleListComponent class]]) {
+        return self;
+    }
+    if ([self.ref isEqualToString:WX_SDK_ROOT_REF]) {
+        return nil;
+    }
+    return [self.supercomponent getRecycleListComponent];
+}
+
 @end
 
 @implementation WXTouchGestureRecognizer

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h 
b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
index 77fec46..9d7cece 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.h
@@ -18,6 +18,7 @@
  */
 
 #import <Foundation/Foundation.h>
+#import <JavaScriptCore/JavaScriptCore.h>
 
 @class WXBridgeMethod;
 @class WXSDKInstance;
@@ -142,6 +143,14 @@ extern void WXPerformBlockOnBridgeThread(void 
(^block)(void));
 - (void)fireEvent:(NSString *)instanceId ref:(NSString *)ref type:(NSString 
*)type params:(NSDictionary *)params domChanges:(NSDictionary *)domChanges 
handlerArguments:(NSArray *)handlerArguments;
 
 /**
+ * componentHook
+ * @param instanceId  : instance id
+ * @param componentId : compoent id
+ * @param type        : component hook Type, such as life-cycle
+ * @param hookPhase   : hook phase
+ */
+- (void)callComponentHook:(NSString*)instanceId 
componentId:(NSString*)componentId type:(NSString*)type 
hook:(NSString*)hookPhase args:(NSArray*)args competion:(void (^)(JSValue * 
value))complection;
+/**
  *  callBack
  *
  *  @param instanceId instanceId

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m 
b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
index 896bed7..c77bdde 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
@@ -326,6 +326,20 @@ void WXPerformBlockOnBridgeThread(void (^block)(void))
     [self callJsMethod:method];
 }
 
+- (void)callComponentHook:(NSString*)instanceId 
componentId:(NSString*)componentId type:(NSString*)type 
hook:(NSString*)hookPhase args:(NSArray*)args competion:(void (^)(JSValue * 
value))complection
+{
+    WXPerformBlockOnBridgeThread(^{
+        if (!type || !instanceId || !hookPhase) {
+            WXLogError(@"type and instance id and hookPhase should not be 
nil");
+            return;
+        }
+        NSArray *newArgs = @[componentId, type, hookPhase, args?:@[]];
+        
+        WXCallJSMethod * method = [[WXCallJSMethod alloc] 
initWithModuleName:nil methodName:@"componentHook" arguments:newArgs 
instance:[WXSDKManager instanceForID:instanceId]];
+        [self.bridgeCtx callJSMethod:@"callJS" args:@[instanceId, 
@[method.callJSTask]] onContext:nil completion:complection];
+    });
+}
+
 - (void)callBack:(NSString *)instanceId funcId:(NSString *)funcId 
params:(id)params keepAlive:(BOOL)keepAlive
 {
     NSArray *args = nil;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m 
b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
index 446e01c..1413402 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
@@ -429,7 +429,6 @@ static css_node_t * rootNodeGetChild(void *context, int i)
     
     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];
@@ -460,7 +459,8 @@ static css_node_t * rootNodeGetChild(void *context, int i)
     [attributesOrStyles enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull 
attributeOrStyleName, id  _Nonnull attributeOrStyle, BOOL * _Nonnull stop) {
         if ([WXBindingMatchIdentify isEqualToString:attributeOrStyleName] // 
match
             ||  [WXBindingRepeatIdentify isEqualToString:attributeOrStyleName] 
// repeat
-            || ([attributeOrStyle isKindOfClass:[NSDictionary class]] && 
attributeOrStyle[WXBindingIdentify])) {  // {"attributeOrStyleName": 
{"@binding":"bindingExpression"}
+            ||  [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]]) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/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
index aaf04d1..3f4f1ce 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
@@ -199,6 +199,9 @@
 
 //    [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];
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m 
b/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
index edb0597..3b22b84 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
@@ -28,6 +28,8 @@
 #import "WXRuleManager.h"
 #import "WXSDKInstance.h"
 #import "WXTracingManager.h"
+#import "WXRecycleListComponent.h"
+#import <objc/message.h>
 
 @interface WXDomModule ()
 
@@ -51,6 +53,7 @@ WX_EXPORT_METHOD(@selector(updateStyle:styles:))
 WX_EXPORT_METHOD(@selector(updateAttrs:attrs:))
 WX_EXPORT_METHOD(@selector(addRule:rule:))
 WX_EXPORT_METHOD(@selector(getComponentRect:callback:))
+WX_EXPORT_METHOD(@selector(updateComponentData:componentData:callback:))
 
 - (void)performBlockOnComponentManager:(void(^)(WXComponentManager *))block
 {
@@ -223,6 +226,19 @@ WX_EXPORT_METHOD(@selector(getComponentRect:callback:))
     }];
 }
 
+- (void)updateComponentData:(NSString*)componentDataId 
componentData:(NSDictionary*)componentData callback:(NSString*)callbackId
+{
+    NSString *recycleListComponentRef = [[componentDataId 
componentsSeparatedByString:@"@"] objectAtIndex:0];
+    if (!recycleListComponentRef) {
+        return;
+    }
+    SEL selector = _cmd;
+    [self performBlockOnComponentManager:^(WXComponentManager * manager) {
+        WXRecycleListComponent * recycleListComponent = 
(WXRecycleListComponent*)[manager componentForRef:recycleListComponentRef];
+        
((void*(*)(id,SEL,NSString*,NSDictionary*,NSString*))objc_msgSend)(recycleListComponent,
 selector, componentDataId, componentData,callbackId);
+    }];
+}
+
 - (void)destroyInstance
 {
     [self performBlockOnComponentManager:^(WXComponentManager *manager) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31458ac/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m 
b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
index be27ae7..e066a14 100644
--- a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
+++ b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
@@ -25,6 +25,7 @@
 #import "WXSDKInstance_private.h"
 #import "WXTransform.h"
 #import "WXTracingManager.h"
+#import "WXSDKManager.h"
 
 #define WX_BOARD_RADIUS_RESET_ALL(key)\
 do {\
@@ -329,6 +330,9 @@ do {\
     }
     
     [_view removeFromSuperview];
+    if (self->_isTemplate && self.attributes[@"@templateId"]) {
+        [[WXSDKManager bridgeMgr] 
callComponentHook:self.weexInstance.instanceId 
componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"detach" 
args:nil competion:nil];
+    }
     _view = nil;
     [_layer removeFromSuperlayer];
     _layer = nil;

Reply via email to