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).