Xamarin.Forms中NSDate格式化触发ObjectDisposedException问题排查
问题:Unix时间戳格式化方法抛出ObjectDisposedException异常
我有一个将UnixTimestamp格式化为日期的方法如下:
public string ConvertDateTimeToDeviceShortDateFormat(double unixTimestamp) { using (var dateInNsDate = NSDate.FromTimeIntervalSince1970(unixTimestamp)) { using (var formatter = new NSDateFormatter()) { formatter.TimeStyle = NSDateFormatterStyle.None; formatter.DateStyle = NSDateFormatterStyle.Short; formatter.Locale = NSLocale.CurrentLocale; return formatter.ToString(dateInNsDate); } } }
该方法在Xamarin.Forms应用中每秒被调用一次,有时会抛出ObjectDisposedException异常,异常堆栈如下:
Xamarin Exception Stack: System.ObjectDisposedException: Cannot access a disposed object. Object name: 'Foundation.NSDate'. at ObjCRuntime.ThrowHelper.ThrowObjectDisposedException (System.Object o) <0x101ca8be0 + 0x00038> in <153620f857f54f9c9ab1e7a1e6853772#0f6f385f46b536c4b979ed569af516e5>:0 at ObjCRuntime.NativeObjectExtensions.GetNonNullHandle (ObjCRuntime.INativeObject self, System.String argumentName) <0x101ca5d70 + 0x00077> in <153620f857f54f9c9ab1e7a1e6853772#0f6f385f46b536c4b979ed569af516e5>:0 at Foundation.NSDateFormatter.ToString (Foundation.NSDate date) <0x101c1f920 + 0x00027> in <153620f857f54f9c9ab1e7a1e6853772#0f6f385f46b536c4b979ed569af516e5>:0
请问每次调用时释放NSDate对象是否存在问题?
问题分析与解决方案
核心问题
NSDate无需手动释放:
NSDate.FromTimeIntervalSince1970创建的对象由Xamarin的GC和iOS的ARC共同管理生命周期,手动用using语句提前释放会导致底层Native对象被销毁,而NSDateFormatter.ToString内部可能仍在访问该对象(即使代码看起来是同步执行,Xamarin绑定层可能存在延迟释放的情况),从而抛出ObjectDisposedException。NSDateFormatter重复创建性能低下:
NSDateFormatter是重量级对象,每秒创建一次会大幅消耗系统资源,同时增加GC压力,甚至可能引发线程安全问题。
修复后的代码
// 全局缓存NSDateFormatter,避免重复创建 private static readonly NSDateFormatter _shortDateFormatter; // 静态构造函数中初始化一次 static YourClassName() { _shortDateFormatter = new NSDateFormatter(); _shortDateFormatter.TimeStyle = NSDateFormatterStyle.None; _shortDateFormatter.DateStyle = NSDateFormatterStyle.Short; _shortDateFormatter.Locale = NSLocale.CurrentLocale; } public string ConvertDateTimeToDeviceShortDateFormat(double unixTimestamp) { // 无需using包裹NSDate,由GC自动管理 var dateInNsDate = NSDate.FromTimeIntervalSince1970(unixTimestamp); return _shortDateFormatter.ToString(dateInNsDate); }
额外注意事项
- 如果方法在多线程环境下调用,
NSDateFormatter不是线程安全的,需要改用ThreadLocal<NSDateFormatter>来为每个线程单独缓存实例,避免并发访问问题。 - 若需要适配系统语言或区域设置变化,需监听
NSLocale.CurrentLocale的变化事件,重新初始化格式化器。
内容的提问来源于stack exchange,提问作者idenardi
相关产品推荐
相关产品推荐

