When exposing .NET classes to Objective-C, a common task is to subclass existing Objective-C classes. The most trivial example is an application controller which is almost present in every single Cocoa application.

The follwing rules apply when overriding an existing Objective-C wrapper's method:

  • The method MUST have the same signature
  • The method MUST have the same ObjectiveCMessage attribute (same declared selector)
  • The method MAY call the base implementation by using a super message calling, if needed
  • The method SHOULD NEVER call the base implementation by using the .NET base keyword.

NSObject subclassing

This is the most frequent subclassing. The following example shows a stub for an NSObject subclass. Some of the methods may or may not be used, according to your choices:

using System;
using Monobjc.AppKit;
using Monobjc.Foundation;

namespace Monobjc.Samples.TLayer
{
    [ObjectiveCClass]
    public class AppDelegate : NSObject
    {
        private static readonly Class AppDelegateClass = Class.Get(typeof (AppDelegate));

        public AppDelegate() {}

        public AppDelegate(IntPtr nativePointer) : base(nativePointer) {}

        [ObjectiveCMessage("init")]
        public override void Init()
        {
            this.NativePointer = this.SendMessageSuper(AppDelegateClass, "init");
            // ...
            // Do additional initialization
            // ...
            return this;
        }

        [ObjectiveCMessage("dealloc")]
        public override void Dealloc()
        {
            // ...
            // Do cleanup
            // ...
            this.SendMessageSuper(AppDelegateClass, "dealloc");
        }

        [ObjectiveCMessage("showTLayerDemoWindow:")]
        public void ShowTLayerDemoWindow(Id sender)
        {
            // ...
        }
    }
}

NSView subclassing

This is also a frequent subclassing. The following example shows a stub for an NSView subclass. It is important to correctly override the InitWithFrame method as it is used to build the view (either directly or from a NIB file).

using System;
using Monobjc.AppKit;
using Monobjc.Foundation;

namespace Monobjc.Samples.NSSpeechSynthesizerExample
{
    [ObjectiveCClass]
    public class SpeakingCharacterView : NSView
    {
        private static readonly Class SpeakingCharacterViewClass = Class.Get(typeof (SpeakingCharacterView));

        public SpeakingCharacterView() {}

        public SpeakingCharacterView(IntPtr nativeObject) : base(nativeObject) {}

        [ObjectiveCMessage("initWithFrame:")]
        public override Id InitWithFrame(NSRect frame)
        {
            this.NativePointer = this.SendMessageSuper(SpeakingCharacterViewClass, "initWithFrame:", frame);
            // ...
            // Do additional initialization
            // ...
            return this;
        }

        [ObjectiveCMessage("dealloc")]
        public override void Dealloc()
        {
            // ...
            // Do cleanup
            // ...
            this.SendMessageSuper(SpeakingCharacterViewClass, "dealloc");
        }

        [ObjectiveCMessage("drawRect:")]
        public override void DrawRect(NSRect rect)
        {
            // If you need to call the base implementation, the use the following statement
            this.SendMessageSuper(SpeakingCharacterViewClass, "drawRect:", rect);

            // ...
            // Do actual drawing
            // ...
        }
    }
}

Other subclassing

For every other subclassing, please refer to the Apple documentation. Here is a rule of thumb to use if unsure: if Apple gives subclassing tips, then go ahead . If not don't subclass (class cluster for example, are never subclassed as it implies a tons of code).