请教一下原生环境下的setTimeOut空指针崩溃问题

比如游戏有两个场景,一个是游戏大厅,另外一个是游戏场景。现在有这么一个问题,就是游戏场景中用了一些setTimeOut,setTimeOut里有对Label控件的string进行赋值操作。如果setTimeOut运行结束后,用户按返回按钮回到游戏大厅,自然是没问题。但如果是setTimeOut还没结束,用户就按返回按钮回到游戏大厅,势必会导致出现空指针问题(因为此时游戏场景中的Label控件已经销毁了)。这个问题类似于java里的子线程变成了野线程的问题。

我发现,在小游戏平台,即使出现了上述setTimeOut的空指针问题,游戏也不会崩溃。但发布到原生平台下,如果出现了setTimeOut的空指针问题,游戏就崩溃了。

请问大家怎样处理这种问题呢?我最容易想到的方法应该是setTimeOut处理如果没结束的话,禁止用户点击返回按钮。我cocos creator不熟,不知道cocos creator有没有什么特殊的更简单方法来处理这种问题,请多指教,谢谢!

1赞

cc.isValid

您的意思是setTimeOut里面,给Label控件的string属性赋值之前先用 cc.isValid来判断Label控件的节点是否为空?就是下面这种伪代码?

setTimeout(() => {
	if  (cc.isValid(node)){
	    Label.string = "100";
	}
}, 10000);

不要用setTimeout和setInterval,用this. schedule和this.scheduleOnce

1赞

现在觉得原生真是有点麻烦,游戏这东西,本来就是为了炫酷的效果,场景里面各种动画,各种setTimeOut处理满天飞。在纯JS的小游戏平台,有setTimeOut导致的空指针什么的,也没事。一发布到原生,这些问题都暴露出来了。
不知道cocos放弃c++改用js,是不是也是有这些考虑。。。。

你想到的cocos引擎开发早就想到了,用cc自己的定时器管理吧

您的意思是cocos 里面,setTimeOut就不能用是吗?这可麻烦了,很多很多地方都用了,要修改的话,程序量比较大了。。。。

我一直以为,cocos切换场景后,以前的场景就废弃了,没有啥野线程(比喻的不太合理,因为JS是单线程)的问题。。。

为了程序规矩,似乎也只能用this. schedule和this.scheduleOnce了。就是看有些帖子说反复调用this. schedule会出错。。。。

setTimeout 不会随着场景的跳转而销毁,最好的方式是使用cocos自带的,这样就不会出现问题,如果非要用原生,记得停止计时器就行

        let timeOut = setTimeout(() => {
            cc.log("亮有一计");
        }, 3000);
        clearTimeout(timeOut);//清除某个timeOut

this.scheduleOnce只能是 cc.Component才能使用,cc.Node没法用,自己定义的工具类里面也没法用,感觉还是无法完全替代setTimeOut啊。。。

写个全局的定时器,注册监听回调 销毁时移除监听回调,并不一定要每次用setTimeOut ,

有的工具类里面,需要用setTimeOut作递归。。。

使用延迟动作代替定时器,节点销毁动作自动跟着销毁
场景内相关的逻辑里从不用全局定时器

  1. 全局定时器 cc.director.getScheduler和cc.Component的schedule是同一个。

  2. 非cc.component里也能用,需要加一行。
    scheduler.enableForTarget(this);

3.node销毁时会自动移除掉scheduler。
image

  1. 用cc.isValid 可以用在cc.loader动态加载,setTimeOut等延迟执行时node已被销毁找不到组件或变量的场合。
2赞

非常感谢这么详细的回复!

您好,不好意思再请教一下,我是在自己定义的Node类里面想实现定时器。现在有点糊涂。
您说的非cc.component里也能用是吧,所以我按照您说的,在自定义的Node类里的构造函数ctor里先cc.director.getScheduler().enableForTarget(this);这里的this是Node节点自己。然后调用cc.director.getScheduler().schedule实现自己的定时部分。

现在糊涂的是
第一:cc.director.getScheduler().schedule报错 cc.Scheduler: Illegal target which doesn’t have uuid or instanceId

第二:cc.director.getScheduler()只有schedule方法,而为什么没有scheduleOnce方法?


可以看看