Нет конструктора для ViewController::. Ctor (System.IntPtr)

У меня возникла проблема, когда мое приложение 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 получает сбор мусора.

Любые идеи?

Ответ 1

Конструктор IntPtr используется, когда нативный объект должен быть обработан управляемым объектом. В этом конкретном случае вы можете создавать, например:

 var foo = new Foo ();
 SomeObject.Property = foo;

Это присваивает объекту Foo свойство, но если свойство является объектом 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 в управляемом коде, чтобы предотвратить сбор объекта, когда вы еще собираетесь его использовать позже.