CocosCreator 对UI的引用思考

UI和代码结合的弊端

1.大量通过界面引用UI节点

如下图所示,通过脚本组件大量直接引用UI节点,会在相应的描述文件中记录相应的key和value,在一定程度上会增加相关描述文件的大小,从而影响这个描述文件加载所花费的时间。进一步影响资源加载总时间。

{
   "__type__": "85d24iUBchG45eRtzPrngjE", 
    "_name": "", 
    "_objFlags": 0, 
    "node": {
        "__id__": 1
    }, 
    "_enabled": true, 
    "label": {
        "__id__": 7
    }, 
    "node1": {
        "__id__": 9
    }, 
    "node2": {
        "__id__": 12
    }, 
    "_id": ""}

通过脚本组件大量直接引用UI节点这种方式还有一个弊端,当节点上的脚本组件因某种原因丢失或者说被重置了,那么还需要被重新挂载一次,如果时间长了,可能都忘记了谁对应的谁。


2.代码中大量查找节点

第一种方式,代码中通过 getChildByName, getChildByUuid 函数查到相应的节点, 在此以 getChildByName 函数来举例。通过下面代码可以看出,正序遍历查找相应节点的名字,返回第一个查到的节点。

/**
 * !#en Returns a child from the container given its name.
 * !#zh 通过名称获取节点的子节点。
 * @method getChildByName
 * @param {String} name - A name to find the child node.
 * @return {Node} a CCNode object whose name equals to the input parameter
 * @example
 * var child = node.getChildByName("Test Node");
 */
getChildByName (name) {
    if (!name) {
        cc.log("Invalid name");
        return null;
    }
    var locChildren = this._children;
    for (var i = 0, len = locChildren.length; i < len; i++) {
        if (locChildren[i]._name === name)
            return locChildren[i];
    }
    return null;
}

举个例子:如下所示,一个根节点下依次有节点A,节点B,节点C,节点D 四个子节点。现在通过 getChildByName 来获取 节点D。


--根节点
----子节点A
----子节点B
----子节点C
----子节点D

如果现在需要查找子节点A呢:

第一次遍历: 查找子节点A,满足条件,则返回子节点A

也就是说 getChildByName 查找子节点A的时间复杂度为1。

如果现在需要查找子节点D呢:

第一次遍历: 查找子节点A,不满足条件,则继续遍历查找
第二次遍历: 查找子节点B,不满足条件,则继续遍历查找
第三次遍历: 查找子节点C,不满足条件,则继续遍历查找
第四次遍历: 查找子节点D,不满足条件,则返回子节点D

也就是说 getChildByName 查找子节点A的时间复杂度为4。

综上所述: getChildByName 查找相应的节点的时间复杂度为 N。意味得查找的节点广度大,所需要的时间越长。代码中大量通过 getChildByName , getChildByUuid 函数查到相应的节点是一个影响性能的因子。


第二种方式,代码中通过 cc.find 函数查到相应的节点,从下面代码可以看出,两层正序遍历查找相应的节点。第一层正序遍历的因子是传入的路径分割。第二层正序遍历的因子是节点的children。

/**
 * Finds a node by hierarchy path, the path is case-sensitive.
 * It will traverse the hierarchy by splitting the path using '/' character.
 * This function will still returns the node even if it is inactive.
 * It is recommended to not use this function every frame instead cache the result at startup.
 *
 * @method find
 * @static
 * @param {String} path
 * @param {Node} [referenceNode]
 * @return {Node|null} the node or null if not found
 */
cc.find = module.exports = function (path, referenceNode) {
    if (path == null) {
        cc.errorID(5600);
        return null;
    }
    if (!referenceNode) {
        var scene = cc.director.getScene();
        if (!scene) {
            if (CC_DEV) {
                cc.warnID(5601);
            }
            return null;
        }
        else if (CC_DEV && !scene.isValid) {
            cc.warnID(5602);
            return null;
        }
        referenceNode = scene;
    }
    else if (CC_DEV && !referenceNode.isValid) {
        cc.warnID(5603);
        return null;
    }
    var match = referenceNode;
    var startIndex = (path[0] !== '/') ? 0 : 1; // skip first '/'
    var nameList = path.split('/');
    // parse path
    for (var n = startIndex; n < nameList.length; n++) {
        var name = nameList[n];
        var children = match._children;
        match = null;
        for (var t = 0, len = children.length; t < len; ++t) {
            var subChild = children[t];
            if (subChild.name === name) {
                match = subChild;
                break;
            }
        }
        if (!match) {
            return null;
        }
    }
    return match;
};

举个例子:如下所示,现在一个场景上的节点关系如下。

-- 场景根节点
---- 子节点A
----- 子节点A1
--- 子节点B
--- 子节点C
----- 子节点C1
--- 子节点D
----- 子节点D1
----- 子节点D2

如果现在需要查找子节点A1呢(暂不考虑第二个参数的情况下):

cc.find('子节点A/子节点A1') 开始遍历是 names  = [子节点A,子节点A1]

第一层第一次遍历: 找到子节点A,满足条件,则进行第二层遍历。

第二层第一次遍历: 找到子节点A1,满足条件,则返回。

也就是说 cc.find 查找子节点A1 的时间复杂度为2。

如果现在需要查找子节点D2呢(暂不考虑第二个参数的情况下):

cc.find(‘子节点D/子节点D2’) 开始遍历是 names = [子节点D,子节点D2]

第一层第一次遍历: 找到子节点A,不满足条件,则继续遍历。

第一层第一次遍历: 找到子节点B,不满足条件,则继续遍历。

第一层第一次遍历: 找到子节点C,不满足条件,则继续遍历。

第一层第一次遍历: 找到子节点D,满足条件,则进行第二层遍历。

第二层第一次遍历: 找到子节点D1,不满足条件,则继续。

第二层第一次遍历: 找到子节点D2,满足条件,则返回。

也就是说 cc.find 查找子节点D2的时间复杂度为6

综上所述: cc.find 查找一次节点的时间复杂度为 C(2 n)=n*(n-1)/(2*1)。意味着查找的节点广度越大和深度越深所需要的时间越长。代码中大量通过 cc.find 函数查到相应的节点是一个影响性能的因子。

无论是第一种方式还是第二种方式在代码中引用相关的节点,如果由于某种原因,修改了节点之间的关系,进而查不到相应的节点引发的错误。还需要重新修改查找相应节点的路径。


3. 大量通过界面引用UI节点 和 代码中大量查找节点

通过这种方式来查找节点,同时具有上面两种方法的弊端。更重要的是同时通过界面引用UI节点和代码中查找UI节点,是不是感觉有点乱。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值