我遇到一个问题,我的Monotouch应用程序有时会在收到内存警告后崩溃。请看下面的堆栈跟踪。
Received memory warning. Level=2 DTMobileIS[2299] : _memoryNotification : { OSMemoryNotificationLevel = 2; timestamp = "2011-04-11 14:29:09 +0000"; } Toplevel exception: System.MissingMethodException: No constructor found for Myapp.UI.BoardController::.ctor(System.IntPtr) at System.Activator.CreateInstance (System.Type type, BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) [0x00000] in :0 at System.Activator.CreateInstance (System.Type type, System.Object[] args, System.Object[] activationAttributes) [0x00000] in :0 at System.Activator.CreateInstance (System.Type type, System.Object[] args) [0x00000] in :0 at MonoTouch.ObjCRuntime.Runtime.ConstructNSObject (IntPtr ptr, IntPtr klass) [0x00000] in :0 at MonoTouch.ObjCRuntime.Runtime.GetNSObject (IntPtr ptr) [0x00000] in :0 at MonoTouch.ObjCRuntime.Runtime.GetNSObjectWrapped (IntPtr ptr) [0x00000] in :0 at (wrapper native-to-managed) MonoTouch.ObjCRuntime.Runtime:GetNSObjectWrapped (intptr) at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00000] in :0 at Myapp.Free.Application.Main (System.String[] args) [0x00000] in /Users/haakon/Code/Myapp-work/iOS/Myapp.Free/Myapp.Free/Main.cs:12
堆栈跟踪是正确的,因为指示的类(BoardController,它是一个UIViewController子类)缺少一个采用IntPtr参数的构造函数。但这是故意的,因为我在我的应用程序中根本不使用Interface Builder。那么为什么会这样呢?
我确实发现了一个类似的问题,似乎暗示如果您允许您的视图(或可能是视图控制器)变成垃圾回收,就会发生这种情况。但我不明白这是怎么发生的。一些背景知识:我的应用程序委托对导航控制器有强烈的引用,导航控制器又对导航堆栈中的根视图控制器进行强引用。此根视图控制器还拥有对BoardController实例的强引用。所以我不明白BoardController是如何收集垃圾的。
有什么想法吗?
答案 0 :(得分:9)
当需要将本机对象浮出到托管对象时,使用IntPtr构造函数。在这种特殊情况下,您可以创建,如下所示:
var foo = new Foo ();
SomeObject.Property = foo;
这会将Foo对象分配给属性,但如果Property是Objective-C对象,如果你没有保留对“foo”的引用,那么Mono的GC将继续处理托管Foo和之间的链接。不受管理的Foo。
然后,稍后,您尝试检索它:
var bar = SomeObject.Property;
在这里,MonoTouch将知道没有托管对象而不是映射到它,因此它必须构造一个新的托管对象,但它只有IntPtr到Objective-C代码。这就是你需要构造函数的原因。
您可能只想添加本机构造函数,这在很多情况中都很好,但如果您的对象在托管环境中存储了自己的状态,则会出现问题,例如:
public class Foo : UIView {
string Name;
public Foo () { Name= "Hello"; }
public Foo (IntPtr ptr) : base (ptr) {}
}
在这种情况下,IntPtr构造函数不能仅从IntPtr完全重建托管对象及其状态。因此,问题的可能来源是您没有保留对象的引用。
所以真正的解决方法就是:在托管代码中保留对BoardController的引用,以防止在以后仍然使用它时收集对象。