This page is likely outdated (last edited on 11 May 2011). Visit the new documentation for updated content.

MonoMac/Documentation/Binding New Objective-C Types/Binding Details

Binding Details

These are the details of how the binding takes place.

It is possible to use the [Register] attribute, [Export] attribute, and manual Objective-C selector invocation together to manually bind new (previously unbound) Objective-C types.

First, find a type that you wish to bind. For discussion purposes (and simplicity), we’ll bind the NSEnumerator type (which has already been bound in MonoMac.Foundation.NSEnumerator; the implementation below is just for example purposes).

Second, we need to create the C# type. We’ll likely want to place this into a namespace; since Objective-C doesn’t support namespaces, we’ll need to use the [Register] attribute to change the type name that MonoTouch will register with the Objective-C runtime. The C# type must also inherit from MonoMac.Foundation.NSObject:

namespace MonoMac.Example.Binding {
    [Register("NSEnumerator")]
    class NSEnumerator : NSObject
    {
        // see steps 3-5
    }
}

Third, review the Objective-C documentation and create MonoMac.ObjCRuntime.Selector instances for each selector you wish to use. Place these within the class body:

static Selector selInit       = new Selector("init");
static Selector selAllObjects = new Selector("allObjects");
static Selector selNextObject = new Selector("nextObject");

Fourth, your type will need to provide constructors. You must chain your constructor invocation to the base class constructor. The [Export] attributes permit Objective-C code to call the constructors with the specified selector name:

[Export("init")]
public NSEnumerator()
    : base(NSObjectFlag.Empty)
{
    Handle = Messaging.IntPtr_objc_msgSend(this.Handle, selInit.Handle);
}
 
// This constructor must be present so that MonoTouch
// can create instances of your type from Objective-C code.
public NSEnumerator(IntPtr handle)
    : base(handle)
{
}

Fifth, provide methods for each of the Selectors declared in Step 3. These will use objc_msgSend() to invoke the selector on the native object. Note the use of Runtime.GetNSObject() to convert an IntPtr into an appropriately typed NSObject (sub-)type. If you want the method to be callable from Objective-C code, the member must be virtual.

[Export("nextObject")]
public virtual NSObject NextObject()
{
    return Runtime.GetNSObject(
        Messaging.IntPtr_objc_msgSend(this.Handle, selNextObject.Handle));
}
 
// Note that for properties, [Export] goes on the get/set method:
public virtual NSArray AllObjects {
    [Export("allObjects")]
    get {
        return (NSArray) Runtime.GetNSObject(
            Messaging.IntPtr_objc_msgSend(this.Handle, selAllObjects.Handle));
    }
}

Putting it all together:

using System;
using MonoTouch.Foundation;
using MonoTouch.ObjCRuntime;
 
namespace MonoTouch.Example.Binding {
    [Register("NSEnumerator")]
    class NSEnumerator : NSObject
    {
        static Selector selInit       = new Selector("init");
        static Selector selAllObjects = new Selector("allObjects");
        static Selector selNextObject = new Selector("nextObject");
 
        [Export("init")]
        public NSEnumerator()
            : base(NSObjectFlag.Empty)
        {
            Handle = Messaging.IntPtr_objc_msgSend(this.Handle,
                selInit.Handle);
        }
 
        public NSEnumerator(IntPtr handle)
            : base(handle)
        {
        }
 
        [Export("nextObject")]
        public virtual NSObject NextObject()
        {
            return Runtime.GetNSObject(
                Messaging.IntPtr_objc_msgSend(this.Handle,
                    selNextObject.Handle));
        }
 
        // Note that for properties, [Export] goes on the get/set method:
        public virtual NSArray AllObjects {
            [Export("allObjects")]
            get {
                return (NSArray) Runtime.GetNSObject(
                    Messaging.IntPtr_objc_msgSend(this.Handle,
                        selAllObjects.Handle));
            }
        }
    }
}