view dstep/objc/bridge/Bridge.d @ 19:ae08a08f44d3

Added IBOutlet
author Jacob Carlborg <doob@me.com>
date Sun, 17 Jan 2010 16:25:24 +0100
parents b2693af5a569
children 6255d355d752
line wrap: on
line source

/**
 * Copyright: Copyright (c) 2009 Jacob Carlborg.
 * Authors: Jacob Carlborg
 * Version: Initial created: Feb 4, 2009
 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
 */
module dstep.objc.bridge.Bridge;

version (Tango)
{
	import tango.core.Memory;
	import tango.core.Traits : ParameterTupleOf, ReturnTypeOf;
}

else
{
	import GC = std.gc : addRoot;
	import std.traits : ParameterTypeTuple, ReturnType;

	alias ReturnType ReturnTypeOf;
	alias ParameterTypeTuple ParameterTupleOf;
}

import dstep.internal.String;
import dstep.internal.Version;
import dstep.objc.bridge.Capsule;
import dstep.objc.bridge.ClassInitializer;
import dstep.objc.bridge.Type;
import dstep.objc.bridge.TypeEncoding;
import dstep.objc.bridge.Wrapper;
import dstep.objc.message;
import dstep.objc.objc;
import dstep.objc.runtime;

/**
 * Builds a string representing a selector out of the given method
 * 
 * It will build the string using the parameter names as a part of the selector,
 * like this:
 * 
 * Examples:
 * ---
 * foo (int x, int y);
 * bar ();
 * fooBar (int x);
 * 
 * static assert(selectorAsString!(foo) == "foo:y:");
 * static assert(selectorAsString!(bar) == "bar");
 * static assert(selectorAsString!(fooBar) == "fooBar:");
 * ---
 * 
 * Params:
 *     method = the method alias to build the selector of
 *     
 * Returns: a string representing the selector
 */
template selectorAsString (alias method)
{
	const selectorAsString = buildSelector!(method);
}

/**
 * Registers a method with the Objective-C runtime system,
 * maps the method name to a selector, and returns the selector value.
 * 
 * You must register a method name with the Objective-C runtime system to obtain
 * the method’s selector before you can add the method to a class definition.
 * If the method name has already been registered, this function simply returns
 * the selector.
 * 
 * Examples:
 * ---
 * SEL sel = selector!("foo:");
 * ---
 * 
 * Params:
 *     str = the string to register
 * 
 * Returns: a pointer of type SEL specifying the selector for the named method.
 */
SEL selector (string str) ()
{
	return sel.registerName!(str);
}

/**
 * Registers a method with the Objective-C runtime system,
 * maps the method name to a selector, and returns the selector value.
 * 
 * Using selectorAsString to get the string representation of the selector.
 * 
 * You must register a method name with the Objective-C runtime system to obtain
 * the method’s selector before you can add the method to a class definition.
 * If the method name has already been registered, this function simply returns
 * the selector.
 * 
 * Examples:
 * ---
 * foo (int x);
 * SEL sel = selector!(foo);
 * ---
 * 
 * Params:
 *     method = the method to register
 * 
 * Returns: a pointer of type SEL specifying the selector for the named method.
 */
SEL selector (alias method) ()
{
	return sel.registerName!(selectorAsString!(method));
}

/**
 * All Objective-C wrappers should mix in this string.
 * 
 * Mixes in:
 * $(UL
 * 		$(LI $(D_PSYMBOL __objcClass): a class variable representing the Objective-C class)
 * 		$(LI $(D_PSYMBOL __objcSuperClass): a class variable representing the Objective-C super class)
 * 		$(LI A constructor taking an Objective-C instance)
 * 		$(LI $(D_PSYMBOL dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer))
 * )
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		mixin(ObjcWrap);
 * }
 * ---
 */
const ObjcWrap = "static private dstep.objc.objc.Class __objcClass;
	static private dstep.objc.objc.Class __objcSuperClass;
			
	this (dstep.objc.objc.id object)
	{
		super(object);
	}	
				
	static typeof(this) alloc ()
	{
		return invokeObjcSelfClass!(typeof(this), \"alloc\");
	}
		
	mixin dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer!(this.stringof, super.stringof);";

/**
 * All Objective-C wrappers should mix in this string.
 * 
 * Mixes in:
 * $(UL
 * 		$(LI $(D_PSYMBOL __objcClass): a class variable representing the Objective-C class)
 * 		$(LI $(D_PSYMBOL __objcSuperClass): a class variable representing the Objective-C super class)
 * 		$(LI A constructor taking an Objective-C instance)
 * 		$(LI $(D_PSYMBOL dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer))
 * ) 
 * 
 * Examples:
 * ---
 * class NSString : NSObject
 * {
 * 		mixin(ObjcClusterWrap);
 * }
 * ---
 */
const ObjcClusterWrap = "static private dstep.objc.objc.Class __objcClass;
	static private dstep.objc.objc.Class __objcSuperClass;
			
	this (dstep.objc.objc.id object)
	{
		super(object);
	}
	
	static typeof(this) alloc ()
	{
		return invokeObjcSuperClass!(typeof(this), \"alloc\");
	}		
			
	mixin dstep.objc.bridge.ClassInitializer.ObjcSubclassInitializer!(this.stringof, super.stringof);";

/**
 * Makes the given field available as an IBOutlet.
 * 
 * Mixes in a method that is called by the Objective-C side to set the value of the
 * given field.
 * 
 * Mixes in: $(D_PSYMBOL ObjcBindMethod)
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		NSButton button;
 * 		mixin IBOutlet!(button);
 * }
 * ---
 * 
 * Params:
 *     field = the field make available as an IBOutlet
 */
template IBOutlet (alias field)
{
	static assert (is(typeof(field) : Object), dstep.objc.bridge.Bridge.buildIBOutletErrorMessage!(field));
	
	void __setMethod (typeof(field) value)
	{
		field = value;
	}
	
	mixin dstep.objc.bridge.Bridge.ObjcBindMethod!(__setMethod, "set" ~ dstep.objc.bridge.Bridge.toUpper(field.stringof[0]) ~ field.stringof[1 .. $] ~ ":");
}

char toUpper (char c)
{
	if (c >= 'a' && c <= 'z')
		return c - 32;
	
	return c;
}

template buildIBOutletErrorMessage (alias field)
{
	const buildIBOutletErrorMessage = `The type "` ~ typeof(field).stringof ~ `" of the given field "` ~ field.stringof ~ `" in the class "` ~ typeof(this).stringof ~ `" is not a valid IBOutlet type. IBOutlets can only be of the type Object (or any of its subclasses)`;
}

/**
 * Binds a selector to an instance method.
 * 
 * This will create a receiver function which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template) to build
 * the selector. It will automatically infer the return type and the argument types
 * of the method. An action method can only have one parameter and of the type Object
 * (or any of its subclasses).
 * 
 * Mixes in: ObjcBindMethod
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		void foo (Object sender) {}
 * 		mixin IBAction!(foo);
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 */
template IBAction (alias method)
{
	static assert (dstep.objc.bridge.Bridge.ParameterTupleOf!(method).length == 1, "An action method is only allowed to have one parameter");
	static assert (is(dstep.objc.bridge.Bridge.ParameterTupleOf!(method)[0] : Object), "An action method can only have a parameter of the type Object (or any of its subclasses)");
	
	mixin ObjcBindMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method));
}

/**
 * Binds a selector to an instance method.
 * 
 * This will create a receiver function which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template) to build
 * the selector. It will automatically infer the return type and the argument types
 * of the method.
 * 
 * Mixes in: ObjcBindMethod
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		void foo () {}
 * 		mixin ObjcBindMethod!(foo);
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 */
template ObjcBindMethod (alias method)
{
	mixin ObjcBindMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method));
}

/**
 * Binds a selector to an instance method.
 * 
 * This will create a receiver function which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * It will automatically infer the return type and the argument types
 * of the method.
 * 
 * Mixes in: ObjcBindMethod
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		void foo () {}
 * 		mixin ObjcBindMethod!(foo, "foo");
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 *     selector = the selector to bind the method to
 */
template ObjcBindMethod (alias method, string selector)
{	
	mixin ObjcBindMethod!(method, dstep.objc.bridge.Bridge.ReturnTypeOf!(method), selector, dstep.objc.bridge.Bridge.ParameterTupleOf!(method));
}

/**
 * Binds a selector to an instance method.
 * 
 * This will create a receiver method which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		int foo (int x)
 * 		{
 * 			return x;
 * 		}
 * 
 * 		mixin ObjcBindMethod!(foo, int, "foo:", int);
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 *     R = the return type of the method
 *     selector = the selector to bind the method to
 *     ARGS = the argument types of the method
 */
template ObjcBindMethod (alias method, R, string selector, ARGS...)
{
	private
	{			
		/**
		 * Resolves the virtual call
		 * 
		 * Returns: a $(D_KEYWORD delegate) to the binded method
		 */
		R delegate (ARGS) __resolveVirtualCall ()
		{
			return &method;
		}
		
		/// A type tuple with all the encapsulated types
		alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs;
		
		/**
		 * The receiver method, this will be the method called from the Objective-C side
		 * 
		 * Params:
		 * 	   self = the Objective-C instance to call the method on
		 * 	   cmd = the Objective-C selector representing the method to call
		 *     objcArgs = the encapsulated arguments to the binded method
		 *     
		 * Returns: whatever the binded method returns, encapsulated
		 */
		extern (C) static dstep.objc.bridge.Type.ObjcType!(R) __forwardVirtualCall (dstep.objc.objc.id self, dstep.objc.objc.SEL cmd, __ObjcArgs objcArgs)
		in
		{
			assert(dstep.objc.bridge.Capsule.isCapsule(self));
		}
		body
		{			
			R delegate (ARGS) delegate () dg;
			dg.ptr = cast(void*) dstep.objc.bridge.Capsule.decapsule!(typeof(this))(self);
			dg.funcptr = &__resolveVirtualCall;					
			ARGS args;
			
			foreach (i, a ; objcArgs)
			{
				alias typeof(args[i]) ArgType;				
				args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a);
			}
			
			static if (is(R == void))
				dg()(args);
			
			else
				return dstep.objc.bridge.Capsule.encapsule!(R)(dg()(args));
		}
		
		/// The Objective-C method declaration for the binded method
		ObjcMethodDeclaration!(__forwardVirtualCall, R, selector, ARGS) __objcMethodDeclaration;
	}
}

/**
 * Binds a selector to a class (static) method.
 * 
 * This will create a receiver function which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * This $(D_KEYWORD template) will use the buildSelector $(D_KEYWORD template)
 * to build the selector. It will automatically infer the return type and the
 * argument types of the method.
 * 
 * Mixes in: $(D_PSYMBOL ObjcBindClassMethod)
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		static void foo () {}
 * 		mixin ObjcBindClassMethod!(foo);
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 */
template ObjcBindClassMethod (alias method)
{
	mixin ObjcBindClassMethod!(method, dstep.objc.bridge.TypeEncoding.buildSelector!(method));
}

/**
 * Binds a selector to a class (static) method.
 * 
 * This will create a receiver function which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * It will automatically infer the return type and the argument types
 * of the method.
 * 
 * Mixes in: $(D_PSYMBOL ObjcBindClassMethod)
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		static void foo () {}
 * 		mixin ObjcBindClassMethod!(foo, "foo");
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 *     selector = the selector to bind the method to
 */
template ObjcBindClassMethod (alias method, string selector)
{
	mixin ObjcBindClassMethod!(method, dstep.objc.bridge.Bridge.ReturnTypeOf!(method), selector, dstep.objc.bridge.Bridge.ParameterTupleOf!(method));
}

/**
 * Binds a selector to a class (static) method.
 * 
 * This will create a receiver method which will forward the call to $(D_PARAM method),
 * decapsulating arguments and encapsulating the return value as appropriate.
 * 
 * Examples:
 * ---
 * class AppController : NSObject
 * {
 * 		static int foo (int x)
 * 		{
 * 			return x;
 * 		}
 * 
 * 		mixin ObjcBindClassMethod!(foo, int, "foo:", int);
 * }
 * ---
 * 
 * Params:
 *     method = the method to bind
 *     R = the return type of the method
 *     selector = the selector to bind the method to
 *     ARGS = the argument types of the method
 */
template ObjcBindClassMethod (alias method, R, string selector, ARGS...)
{
	private
	{
		/// A type tuple with all the encapsulated types
		alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs;
		
		/**
		 * The receiver method, this will be the method called from the Objective-C side
		 * 
		 * Params:
		 *     objcArgs = the encapsulated arguments to the binded method
		 *     
		 * Returns: whatever the binded method returns, encapsulated
		 */
		extern (C) static dstep.objc.bridge.Type.ObjcType!(R) __forwardStaticCall (dstep.objc.objc.Class self, dstep.objc.objc.SEL cmd, __ObjcArgs objcArgs)
		in
		{
			assert(dstep.objc.bridge.Capsule.isCapsule(self));
		}
		body
		{
			R function (ARGS) funcPtr = &method;			
			ARGS args;
			
			foreach (i, a ; objcArgs)
			{
				alias typeof(args[i]) ArgType;				
				args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a);
			}
			
			static if (is(R == void))
				funcPtr()(args);
			
			else
				return dstep.objc.bridge.Capsule.encapsule!(R)(funcPtr()(args));
		}
		
		/// The Objective-C method declaration for the binded method
		ObjcMethodDeclaration!(__forwardStaticCall, R, selector, ARGS) __objcClassMethodDeclaration;
	}
}

/**
 * This $(D_KEYWORD struct) represents an Objective-C method declaration.
 * 
 * Examples:
 * ---
 * class C : NSObject
 * {
 * 		void foo (int x) {}
 * 		ObjcMethodDeclaration!(foo, void, "foo", int) objcMethodDecl;
 * }
 * ---
 * 
 * Params:
 *     imp = the D method
 *     R = the return type of the method
 *     name = the name of the method
 *     ARGS = the argument types of the method
 */
struct ObjcMethodDeclaration (alias imp, R, string name, ARGS...)
{
	dstep.objc.objc.IMP methodImp = cast(dstep.objc.objc.IMP) &imp;
	alias R returnType;
	const string methodName = name;
	alias ARGS argsType;
}

/**
 * Binds a D free function to an Objective-C free function. 
 * 
 * This will create a receiver function which will forward the call to the
 * binded function, decapsulating arguments and encapsulating the return value
 * as appropriate.
 * 
 * Mixes in: $(D_PSYMBOL ObjcBindFunction)
 * 
 * Examples:
 * ---
 * void foo ();
 * mixin ObjcBindFunction!(foo);
 * ---
 */
template ObjcBindFunction (alias func)
{
	mixin ObjcBindFunction!(func, dstep.objc.bridge.Bridge.ReturnTypeOf!(func), dstep.objc.bridge.Bridge.ParameterTupleOf!(func));
}

/**
 * Binds a D free function to an Objective-C free function. 
 * 
 * This will create a receiver function which will forward the call to the
 * binded function, decapsulating arguments and encapsulating the return value
 * as appropriate.
 * 
 * Examples:
 * ---
 * char foo (int);
 * mixin ObjcBindFunction!(foo, char, int);
 * ---
 * 
 * Params:
 *     func = the function to bind
 *     R = the return type of the function
 *     ARGS = the argument types of the function
 */
template ObjcBindFunction (alias func, R, ARGS...)
{
	private
	{		
		/// A type tuple with all the encapsulated types
		alias dstep.objc.bridge.Type.ObjcTypes!(ARGS) __ObjcArgs;
		
		/**
		 * The receiver function, this will be the function called from the Objective-C side
		 * 
		 * Params:
		 *     objcArgs = the encapsulated arguments to the binded function
		 *     
		 * Returns: whatever the binded function returns, encapsulated
		 */
		extern (C) dstep.internal.Types.ObjcType!(R) __forwardFunctionCall (__ObjcArgs objcArgs)
		{			
			R function (ARGS) funcPtr = &func;
			ARGS args;
			
			foreach (i, a ; objcArgs)
			{
				alias typeof(args[i]) ArgType;				
				args[i] = dstep.objc.bridge.Capsule.decapsule!(ArgType)(a);
			}
			
			static if (is(R == void))
				funcPtr()(args);
			
			else
				return dstep.objc.bridge.Capsule.encapsule!(R)(funcPtr()(args));
		}
	}
}

/// This $(D_KEYWORD class) acts like a name space for various methods and functions
class Bridge
{	
	private static Bridge bridgeInstance;
	
	/// The name of the method declaration variable mixed in in a $(D_KEYWORD class)
	const objcMethodDeclarationVar = "__objcMethodDeclaration";
	
	/// The name of the class method declaration variable mixed in in a $(D_KEYWORD class)
	const objcClassMethodDeclarationVar = "__objcClassMethodDeclaration";
	
	/// The name of the variable used on the Objective-C side to store the D object
	const dObjectVar = "dObject";
	
	/// This alias is used as an internal representation of a D object
	//alias Object DObjectType;
	alias void* DObjectType;
	
	/**
	 * Gets the only instance of this class
	 * 
	 * Returns: the instance
	 */
	static Bridge instance ()
	{
		if (bridgeInstance)
			return bridgeInstance; 
		
		return bridgeInstance = new Bridge;
	}
	
	static:
		
	/**
	 * Gets the value of an Objective-C instance variable
	 * 
	 * Examples:
	 * ---
	 * id self;
	 * int x = getObjcIvar!(int, "x")(self);
	 * ---
	 * 
	 * Params:
	 * 	   T = the type of the instance variable
	 * 	   name = the name of the instance variable
	 *     self = the Objective-C instance
	 *     
	 * Returns: the value of the Objective-C variable
	 */
	T getObjcIvar (T, string name) (id self)
	{
		T value;
		
		self.getInstanceVariable!(T, name)(value);
		
		return value;
	}
	
	/**
	 * Sets the value of an Objective-C instance variable
	 * 
	 * Examples:
	 * ---
	 * id self;
	 * Bridge.setObjcIvar!(int, "x")(self, 3);
	 * ---
	 * 
	 * Params:
	 * 	   T = the type of the instance variable
	 * 	   name = the name of the instance
	 *     objcObject = the Objective-C instance
	 *     value = the value to set
	 */
	void setObjcIvar (T, string name) (id self, T value)
	{
		GC.addRoot(value);
		self.setInstanceVariable!(T, dObjectVar)(value);
	}
	
	/**
	 * Gets the D object stored in the given Objective-C instance
	 * 
	 * Examples:
	 * ---
	 * NSObject object = new NSObject;
	 * id self = object.objcObject;
	 * assert(object == Bridge.getDObject(self));
	 * ---
	 * 
	 * Params:
	 *     self = the Objective-C instance 
	 *     
	 * Returns: the D object or null
	 */
	package DObjectType getDObject (id self)
	{
		return getObjcIvar!(DObjectType, dObjectVar)(self);
	}
	
	/**
	 * Stores the given D object in the given Objective-C instance
	 * 
	 * Examples:
	 * ---
	 * NSObject object = new NSObject;
	 * id self = object.objcObject;
	 * Bridge.setDObject(object, self);
	 * ---
	 * 
	 * Params:
	 *     dObject = the D object to store 
	 *     objcObject = the Objective-C instance to store the D object in
	 *     
	 * Returns: the Objective-C instance
	 */
	package id setDObject (Object dObject, id objcObject)
	{
		auto o = cast(DObjectType) dObject;		
		setObjcIvar!(DObjectType, dObjectVar)(objcObject, o);
		
		return objcObject;
	}

	/**
	 * Deregisters the given Objective-C instance from the bridge
	 * 
	 * Params:
	 *     objcInstance = the Objective-C instance to deregister
	 */
	package static void deregisterObjcInstance (id objcInstance)
	{
		GC.removeRoot(getObjcIvar!(DObjectType, dObjectVar)(objcInstance));
	}
	
	/** 
	 * This method wraps the family of $(D_PSYMBOL objc_msgSend) methods which is used to send a message
	 * to an instance of a class.
	 * 
	 * This method chooses the appropriate $(D_PSYMBOL objc_msgSend) method depending on the return value,
	 * decapsulating arguments and encapsulating the return value as appropriate. 
	 * 
	 * Params:
	 * 	   R = the return type
	 * 	   selector = the selector to call
	 * 	   ARGS = the argument types
	 *     self = the reciver of the call
	 *     args = the arguments to the method
	 *     
	 * Returns: whatever the method returns, encapsulaed
	 */
	R invokeObjcMethod (R, string selector, ARGS...) (id self, ARGS args)
	{		
		static assert (checkSelector!(selector, ARGS), "The selector \"" ~ selector ~ "\" and the arguments " ~ ARGS.stringof ~ " do not match");
		
		SEL sel = sel.registerName!(selector);
		ObjcTypes!(ARGS) objcArgs;
		
		foreach (i, a ; args)
		{
			alias typeof(a) ArgType;
			
			objcArgs[i] = encapsule!(ArgType)(a);
		}	
		
		static if (is(R == struct))
		{
			R result;
			self.msgSend_stret(result, sel, objcArgs);
			
			return result;
		}
		
		else static if (is(R == float) || is(R == double) || is(R == real))
		{
			version (X86)
				return self.msgSend_fpret!(R, ObjcTypes!(ARGS))(sel, objcArgs);
			
			else version (X86_64)
			{
				static if (is(R == real))
					return self.msgSend_fpret!(R)(sel, objcArgs);
				
				else
					return self.msgSend!(R)(sel, objcArgs);
			}
			
			else
				return self.msgSend!(R)(sel, objcArgs);
		}
		
		else static if (needsEncapsulation!(R))
			return decapsule!(R)(self.msgSend(sel, objcArgs));
		
		else
			return self.msgSend!(R, ObjcTypes!(ARGS))(sel, objcArgs);
	}
	
	/** 
	 * This method wraps the family of $(D_PSYMBOL objc_msgSend) methods which is used to send a message
	 * to a class.
	 * 
	 * This method chooses the appropriate $(D_PSYMBOL objc_msgSend) method depending on the return value,
	 * decapsulating arguments and encapsulating the return value as appropriate. 
	 * 
	 * Params:
	 * 	   R = the return type
	 * 	   selector = the selector to call
	 * 	   ARGS = the argument types
	 *     cls = the reciver of the call
	 *     args = the arguments to the method
	 *     
	 * Returns: whatever the method returns, encapsulaed
	 */
	R invokeObjcClassMethod (R, string selector, ARGS...) (Class cls, ARGS args)
	{
		return invokeObjcMethod!(R, selector, ARGS)(cast(id) cls, args);
	}
	
	/** 
	 * This method wraps the family of $(D_PSYMBOL objc_msgSendSuper) methods which is used to send a message
	 * to an instance of a superclass.
	 * 
	 * This method chooses the appropriate $(D_PSYMBOL objc_msgSendSuper) method depending on the return value,
	 * decapsulating arguments and encapsulating the return value as appropriate. 
	 * 
	 * Params:
	 * 	   R = the return type
	 * 	   selector = the selector to call
	 * 	   ARGS = the argument types
	 *     self = the reciver of the call
	 *     args = the arguments to the method
	 *     
	 * Returns: whatever the method returns, encapsulaed
	 */
	R invokeObjcSuperMethod (R, string selector, ARGS...) (objc_super* self, ARGS args)
	{		
		static assert (checkSelector!(selector, ARGS), "The selector \"" ~ selector ~ "\" and the arguments " ~ ARGS.stringof ~ " do not match");
		
		SEL sel = sel.registerName!(selector);
		ObjcTypes!(ARGS) objcArgs;
		
		foreach (i, a ; args)
		{
			alias typeof(a) ArgType;
			
			objcArgs[i] = encapsule!(ArgType)(a);
		}
		
		static if (is(R == struct))
		{
			R result;
			self.msgSendSuper_stret(result, sel, objcArgs);
			
			return result;
		}
		
		else static if (needsEncapsulation!(R))
			return decapsule!(R)(self.msgSendSuper(sel, objcArgs));
		
		else
			return self.msgSendSuper!(R, ObjcTypes!(ARGS))(sel, objcArgs);
	}
	
	/**
	 * This method wraps a call to a regular C free function, decapsulating arguments and
	 * encapsulating the return value as appropriate.
	 * 
	 * Params:
	 * 	   R = the return type
	 * 	   func = the function to call
	 * 	   ARGS = the argument types
	 *     args = the arguments to the function
	 *     
	 * Returns: whatever the method returns, encapsulaed
	 */
	R invokeObjcFunction (R, alias func, ARGS...) (ARGS args)
	{		
		auto funcPtr = &func; // use a function pointer instead of the alias because the function may not be public.
		ObjcTypes!(ARGS) objcArgs;
		
		foreach (i, a ; args)
		{
			alias typeof(a) ArgType;
			
			objcArgs[i] = encapsule!(ArgType)(a);
		}
		
		static if (is(R == void))
			funcPtr(objcArgs);
		
		else
			return decapsule!(R)(funcPtr(objcArgs));
	}
}