记一次线上报错 GList AddChildAt NullReferenceException

文章目录

    • 问题描述
    • 分析
    • 结果
    • 总结

问题描述

后台日志大量报错,去主干看无法复现
c# exception:System.NullReferenceException: Object reference not set to an instance of an object. at FairyGUI.GCompone
nt.AddChildAt (FairyGUI.GObject child, System.Int32 index) [0x00000] in <00000000000000000000000000000000>:0 at Fairy
GUI.GList.AddChildAt (FairyGUI.GObject child, System.Int32 index) [0x00000] in <00000000000000000000000000000000>:0 a
t FairyGUI.GComponent.AddChild (FairyGUI.GObject child) [0x00000] in <00000000000000000000000000000000>:0 at FairyGUI
.GList.set_numItems…

分析

看逻辑是没有问题的,但是在调用numItems时c#层报错。看FairyGUI的代码,

public int numItems
{get{if (_virtual)return _numItems;elsereturn _children.Count;}set{if (_virtual){if (itemRenderer == null)throw new Exception("FairyGUI: Set itemRenderer first!");_numItems = value;if (_loop)_realNumItems = _numItems * 6;//设置6倍数量,用于循环滚动else_realNumItems = _numItems;//_virtualItems的设计是只增不减的int oldCount = _virtualItems.Count;if (_realNumItems > oldCount){for (int i = oldCount; i < _realNumItems; i++){ItemInfo ii = new ItemInfo();ii.size = _itemSize;_virtualItems.Add(ii);}}else{for (int i = _realNumItems; i < oldCount; i++)_virtualItems[i].selected = false;}if (_virtualListChanged != 0)Timers.inst.Remove(this.RefreshVirtualList);//立即刷新this.RefreshVirtualList(null);}else{int cnt = _children.Count;if (value > cnt){for (int i = cnt; i < value; i++){if (itemProvider == null)AddItemFromPool();elseAddItemFromPool(itemProvider(i));}}else{RemoveChildrenToPool(value, cnt);}if (itemRenderer != null){for (int i = 0; i < value; i++)itemRenderer(i, GetChildAt(i));}}}
}

AddChild 发生在 AddItemFromPool 中

/// <summary>
/// Add a item to list, same as GetFromPool+AddChild
/// </summary>
/// <returns>Item object</returns>
public GObject AddItemFromPool()
{GObject obj = GetFromPool(null);return AddChild(obj);
}/// <summary>
/// Add a item to list, same as GetFromPool+AddChild
/// </summary>
/// <param name="url">Item resource url</param>
/// <returns>Item object</returns>
public GObject AddItemFromPool(string url)
{GObject obj = GetFromPool(url);return AddChild(obj);
}

AddChild 的参数为空引用, 看GetFromPool如何拿到

public GObject GetFromPool(string url)
{if (string.IsNullOrEmpty(url))url = _defaultItem;GObject ret = _pool.GetObject(url);if (ret != null)ret.visible = true;return ret;
}

最终定位到GObjectPool.GetObject,对象是从对象池池子中取出的,没取到则创建一个

        public GObject GetObject(string url){url = UIPackage.NormalizeURL(url);if (url == null)return null;Queue<GObject> arr;if (_pool.TryGetValue(url, out arr)&& arr.Count > 0)return arr.Dequeue();GObject obj = UIPackage.CreateObjectFromURL(url);if (obj != null){if (initCallback != null)initCallback(obj);}return obj;}

从上面的代码可以得出报错的原因

  1. 可能池子里拿出来的对象在lua层已经被销毁了
  2. 可能创建对象没有成功,资源存在问题

在lua代码报错的地方加入以下定位代码

    local list = self._listviewlocal obj, nullNum, lossNumfor i = list.numChildren + 1, infoLen do -- 先处理已经销毁了的obj, nullNum, lossNum = self:getItmeFromPool(list)if obj thenlist:AddChild(obj)elseif SDKCtrl thenSDKCtrl:reportError(" warning 上报定位  get null tiems:" .. nullNum .. "  get Disposed times: " .. lossNum)endendendlist.numItems = infoLenlist:ResizeToFit(infoLen)
function mod:getItmeFromPool(list)local objlocal lossNum, nullNum = 0, 0while lossNum < 100 and nullNum < 100 doobj = list:GetFromPool()if not obj thennullNum = nullNum + 1elseif obj.isDisposed thenlossNum = lossNum + 1elsebreakendendreturn obj, nullNum, lossNum
end

结果

定位的代码更新出去后,日志中出现了 warning 上报定位 get null tiems:100 get Disposed times: 0。
item对象没有创建成功,是分支的列表item资源存在问题,分支找到对应的包重新发布下,问题解决了。应该是主干同步分支的时候没有发布该包。

总结

GList添加item时候,会从对象池中取一个已存在对象复用或者创建新的对象,如果没有找到对应的资源或者对象池中的对象已经销毁过,会导致创建失败,报错 AddChildAt NullReferenceException。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/608368.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

make的基本操作

./configure --with-name地址 &#xff08;相关库的安装路径&#xff09; make -jn //n指定最大核数 sudo make install //也可以指定安装目录 make install prefix路径 sudo ldconfig

二进制部署

HOST HostnameIP地址flannedAPPmaster192.169.116.10ETCD\APIserver\Scheduler\Controller-Managernode1192.168.116.11172.17.28.0ETCD,Flanned,Kubelet,kube-proxynode2192.168.116.12172.17.26.0ETCD,Flanned,Kubelet,kube-proxy Kubernetes社区 Kubernetes文档 ETCD mas…

微信小程序canvas画布自由绘制/画笔功能实现

.wxml <canvas class="canvas" type="2d" id="myCanvas" bindtouchstart="update_edit_position" bindtouchmove="brush"/> .wxss 定义画布显示样式 .canvas{background-color: white;height: 65vh;width: 100%;m…

大模型时代:AI原生企业的崛起

导读&#xff1a;当前&#xff0c;以大模型为代表的人工智能技术已成为驱动经济社会发展、提升国家竞争力的关键要素&#xff0c;并以前所未有的速度重塑产业的新格局、驱动经济发展的新方向&#xff0c;并展现出强大的赋能效应&#xff0c;给千行百业带来“质量与效率”的变革…

ORPC-824,对标可替代ACPL-824/PC824等

提供隔离反馈 逻辑电路之间的接口 电平转换 DC和AC输入 SMPS中的调节反馈电路 消除接地环路 特征 电流传输比 &#xff08; CTR &#xff1a; 最低 20% 在 IF 1mA&#xff0c; VCE 5V &#xff09; 宽工作温度范围 -55~110C 高输入输出隔离电压 &#xff08; Viso 5&am…

怎么批量创建多个文件夹并命名?

怎么批量创建多个文件夹并命名&#xff1f;在日常的文件管理中&#xff0c;有时候我们需要批量创建多个文件夹并给它们命名&#xff0c;以便更好地组织和分类我们的文件。无论是在工作中还是个人使用中&#xff0c;批量创建文件夹可以帮助我们更高效地整理和管理文件。想象一下…

游戏引擎支持脚本编程有啥好处

很多游戏引擎都支持脚本编程。Unity、Unreal Engine、CryEngine等大型游戏引擎都支持使用脚本编写游戏逻辑和功能。脚本编程通常使用C#、Lua或Python等编程语言&#xff0c;并且可以与游戏引擎的API进行交互来控制游戏对象、设置变量、执行行为等。使用脚本编程&#xff0c;游戏…

c++学习:list链表模板类实战(学生管理系统)

要求&#xff1a; 编写一个学生结构体要求面向对象要求用到链表连接每个学生 代码 #include <iostream> #include <list> using namespace std;class Student {friend istream& operator>>(istream&in,Student &ra);friend bool cmp(Student …

安达发APS|超级BOM是什么?

超级BOM&#xff08;Bill of Materials&#xff09;是一种在制造业中广泛使用的工具&#xff0c;用于管理和控制产品的制造过程。它包含了制造一个产品所需的所有原材料、零部件、组件和组装件的清单&#xff0c;以及它们的数量和规格。超级BOM不仅包括直接用于产品制造的物料&…

2024.1.8 关于 Redis 数据类型 Zset 集合命令、编码方式、应用场景

目录 引言 Zset 集合命令 ZINTERSTORE ZUNIONSTORE Zset 编码方式 Zset 应用场景 排行榜系统 引言 在 Redis 中集合间操作无非就是 交集、并集、差集 Set 类型与之相对应的操作命令为 sinter、sunion、sdiff 注意&#xff1a; 从 Redis 6.2 版本开始&#xff0c;Zset 命…

155. 最小栈

155. 最小栈 题目链接&#xff1a;155. 最小栈 代码如下&#xff1a; class MinStack { public:stack<int> s_stack;stack<int> min_stack;MinStack() {}void push(int val) {s_stack.push(val);if(min_stack.empty()){min_stack.push(val);}else{min_stack.push…

mariadb实现主从同步

准备两台服务器 Mariadb-Master&#xff1a;192.168.44.150 Mariadb-Backup&#xff1a;192.168.44.148 安装mariadb&#xff1a; https://blog.csdn.net/qq_50247813/article/details/135402502?spm1001.2014.3001.5502 组从复制原理如下 修改主数据库配置如下 vi /etc/my.…

游戏、设计选什么内存条?光威龙武系列DDR5量大管饱

如果你是一位PC玩家或者创作者&#xff0c;日常工作娱乐中&#xff0c;确实少不了大容量高频内存的支持&#xff0c;这样可以获得更高的工作效率&#xff0c;光威龙武系列DDR5内存条无疑是理想之选。它可以为计算机提供强劲的性能表现和稳定的运行体验&#xff0c;让我们畅玩游…

【PB续命07】JDBC连接达梦数据库

JDBC(Java DataBase Connectivity) 称为Java数据库连接&#xff0c;它是一种用于数据库访问的应用程序API&#xff0c;由一组用Java语言编写的类和接口组成&#xff0c;有了JDBC就可以用同一的语法对多种关系数据库进行访问&#xff0c;而不用担心其数据库操作语言的差异。 有了…

【我的Rust库】get_local_info 0.1.7发布

大家对我真不错&#xff0c;0.1.6版发布才两天&#xff0c;阅读量已超600。感谢&#xff0c;我的运气真好。 以后会继续带给 Rust爱好者 更多的好东西。 get_local_info是一个获取linux本地信息的Rust三方库&#xff0c;其目标是降低获取本地linux系统信息的难度。支持银河麒…

代理IP中的API提取链的关键作用

在数字时代&#xff0c;互联网已成为我们日常生活和工作中不可或缺的一部分。随着网络技术的不断发展&#xff0c;代理IP作为一种网络协议&#xff0c;越来越受到人们的关注。代理IP可以通过代理服务器转发HTTP、HTTPS等请求&#xff0c;使用户的真实IP地址得以隐藏&#xff0c…

VisualVM 连接到远程服务器

使用 VisualVM 连接到远程服务器的步骤如下&#xff1a; 在远程服务器上启动JMX服务&#xff1a; 在你的 Java 应用程序启动脚本或命令行参数中添加 JMX 参数。示例命令如下&#xff1a; bash复制代码 java -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.…

中国IT产经新闻:新能源汽车发展前景与燃油车的利弊之争

随着科技的进步和环保意识的提高&#xff0c;新能源汽车在全球范围内逐渐受到重视。然而&#xff0c;在新能源汽车迅速发展的同时&#xff0c;燃油车仍然占据着主导地位。本文将从新能源与燃油车的利弊、新能源汽车的发展前景两个方面进行分析&#xff0c;以期为读者提供全面的…

Codeforces Hello 2024 A~D,F1

A.Wallet Exchange(思维) 题意&#xff1a; Alice和Bob各自拥有 a , b a,b a,b枚硬币&#xff0c;他们决定以Alice为先手开始比赛&#xff0c;比赛中每人在每轮需按顺序执行操作1和操作2&#xff1a; 操作1&#xff1a;交换两人手上拥有的硬币数量&#xff0c;或什么都不做 …

用python提取word中的所有图片

使用word中提取的方式图片会丢失清晰度&#xff0c;使用python写一个脚本&#xff0c;程序运行将弹出对话框选择一个word文件&#xff0c;然后在弹出一个对话框选择一个文件夹保存word中的文件。将该word中的所有图片都保存成png格式&#xff0c;并命名成image_i的样式。 程序…