MonoTouch.Foundation.NSObject Class
Base class for all bound objects that map to Objective-C objects.

See Also: NSObject Members

Syntax

[MonoTouch.Foundation.Register("NSObject", true)]
public class NSObject : INSObjectProtocol, IDisposable, IEquatable<NSObject>

Remarks

This is the base class that is used to bind Objective-C classes to C# classes. Merely subclassing from NSObject will produce a class that can be passed to Objective-C.

The C# NSObject class and their subclasses are managed representations of the underlying Objective-C instances. The pointer to the unmanaged code Objective-C object is stored in the NSObject.Handle property.

It is important to note that currently, the compiler does not support generic subclasses of NSObject.

Class Registration

When you create a subclass of NSObject this subclass is registered with the Objective-C runtime with a name based on the full .NET typename which is an implementation detail. If you need to ensure that a C# class is exposed with a specific name in the Objective-C runtime, you can apply the MonoTouch.ObjCRuntime.RegisterAttribute to the class and specify the name that you want your class to have.

The above is typically used in cases where either you want to reference the class by name on some Objective-C code, when using Interface Builder XIB and Storyboard files or when you are using an Objective-C serialization setup (for example when using MonoTouch.Foundation.NSCoder).

c# Example

//
// This exposes the C# class _MySampleView as the Objective-C MyView
//
[Export ("MyView")]
public class _MySampleView : UIView {

}

Objective-C Methods

In general, MonoTouch classes map one to one to the underlying Objective-C classes. For example, the C# class "MonoTouch.Foundation.NSObject" maps to the Objective-C "NSObject" class. But methods are different. The Objective-C methods do not translate well to C# methods, so they have been in general been altered to match both the C# language, the C# idioms and the .NET Framework Design Guidelines.

Objective-C methods are surfaced to C# as virtual methods that have the special MonoTouch.ObjCRuntime.ExportAttribute applied to them. This attribute is used by the compiler to map C# names to Objective-C names. These attributes are shown in the API documentation on top of each function, to help you identify which Objective-C method a particular C# method is calling.

To alter the behavior of a class you use the standard C# idioms: create a subclass and override the methods that you want to alter and use the "base." language feature to optionally call into your base class.

c# Example

public class MyView : UISlider {
	public override void Draw (RectangleF rect)
	{
		// Let the base class draw first
		base.Draw (rect);
	
		// Our custom code
		var ctx = UIGraphics.GetCurrentContext ();
		UIColor.Gray.SetColor ();
		ctx.StrokeEllipseInRect (rect);
	}
}

By default, only methods that have been overwritten will be exposed to the Objective-C world. If you want to expose an arbitrary C# method to the Objective-C world, you need to apply the MonoTouch.ObjCRuntime.ExportAttribute to your public method. And this can be done to both static and instance methods. Once the attribute is applied, the method will be exposed to Objective-C and the standard data type marshalling operations that are supported by the runtime are made available to those methods.

c# Example

//
// Exposes the class StringUtilities to Objective-C with the 
// method:
//    - (NSString *) joinArray:(NSArray *) stringArray withSeparator:(NSString *sep);
//
// Used like this:
//   id utilities = [[StringUtilities alloc] init];
//   NSLog (@"Joined: %@", [utilities joinArray:users withSeparator:@", "]);
//
public class StringUtilities : NSObject {
	[Export ("joinArray:withSeparator:")]
	public string Join (string [] array, string separator)
	{
		return string.Join (separator, array);
	}
}

Lifecycle

The C# NSObject and their subclasses are managed wrappers for the underlying Objective-C object. These are created either from C#, when you create a new instance by using the "new" operator or when an existing unmanaged object is surfaced to the C# world.

When you create an object from C# using the "new" operator, the object will initially be owned by C#, and C# will retain a reference to the object. This reference will only be dropped when the garbage collector determines that there are no pending managed references to it, or when you manually call the Dispose method on the object.

C# NSObjects are also created on demand when you invoke a method or a property that returns an NSObject. At this point, the runtime will look into an object cache and determine whether a given Objective-C NSObject has already been surfaced to the managed world or not. If the object has been surfaced, the existing object will be returned, otherwise a constructor that takes an IntPtr as a parameter is invoked to construct the object.

Pure "peers" to framework objects (those objects that are merely C# representations of an Objective-C object and have no extra managed associated state) can be recreated by the runtime on demand by using the constructor mentioned before.

User-subclasses of NSObjects often contain C# state so whenever the Objective-C runtime performs a "retain" operation on one of these objects, the runtime creates a GCHandle that keeps the managed object alive, even if there are no C# visible references to the object. This simplifies bookeeping a lot, since the state will be preserved automatically for you.

The Dispose operation on an NSObject will always drop the reference to the underlying Objective-C object, but will not destroy the managed state, this will only happen when both the managed code and the unmanaged code have both released the objects. This is slightly different from .NET, because on .NET once an object is disposed, it is not possible to invoke any methods on the object, as it is deemed to be useless. That is not the case with NSObjects.

Adopting Protocols

In MonoTouch, most Objective-C protocols are mapped to classes that have the MonoTouch.ObjCRuntime.ModelAttribute applied to them. And the way that you adopt a protocol is by subclassing and overwriting the methods that you want to adopt.

There are some rare cases, where you want to adopt an ad-hoc protocol on your own. If you need to adopt an Objective-C protocol, you should use the MonoTouch.ObjCRuntime.AdoptsAttribute on your class and provide the name of the protocol that you want to adopt. Typically, when adopting a protocol, you will also have to list all of the Objective-C selectors that you are adopting using the MonoTouch.ObjCRuntime.ExportAttribute.

c# Example

[Adopts ("NSLocking")]
public class MyLockeingObject : NSObject {
	[Export ("lock")]
	public void Lock ()
	{
		// ...
	}

	[Export ("unlock")]
	public void Unlock ()
	{
		// ...
	}
}

Key Value Coding

Key Value coding is a mechanism that allows you to access properties of an object by their name, as opposed to accessing them directly with a C# method.

To expose a C# property to the Key-Value coding system all you need to do is add the MonoTouch.ObjCRuntime.ExportAttribute to your property. The names must only contain ASCII characters, start with a lowercase letter, and must not contain any spaces.

c# Example

public class CircleLayer : CALayer {
	[Export ("radius")]
	public double Radius { get; set; }

	// ...
}

You use the MonoTouch.Foundation.ValueForKey(NSString) to lookup a property using a name, and you use the of functions MonoTouch.Foundation.SetValueForKey(NSObject, MonoTouch.Foundation.NSString) to set the value for the specified property. For example, you could call foo.ValueForKey ("user") to grab the value of the user property in an object.

In addition, you can use Key Paths to have the runtime repeatedly call the ValueForKey or SetValueForKey for you. You separate the keys by using a dot. For example the keypath "user.address.phone.mobile" would request the user property, and then request the address property on the user, then it would request the phone property on the address and finally request the mobile property on the phone and finally use the result as the value. You use the MonoTouch.Foundation.ValueForKeyPath(NSString) to lookup a property using a keypath, and you use the MonoTouch.Foundation.SetValueForKeyPath(NSObject, MonoTouch.Foundation.NSString) to set a value using a keypath.

When using keypaths, if a lookup fails, the NSObject.SetValueForUndefinedKey(NSObject, NSString) will be invoked when setting a value, and the NSObject.ValueForUndefinedKey(NSString) will be invoked when looking up a value. Both methods by default raise an Objective-C exception, you can alter that behavior by overriding the methods.

Key Value Observing

Key value observing is a mechanism implemented by NSObject that can be used to monitor changes being done to an NSObject through the Key Value Coding system.

For your class to observe a notification, you must override the MonoTouch.Foundation.ObserveValue(NSString, NSObject, NSDictionary, IntPtr) method which will be invoked with the information about the value changes for a specific keypath. Then you use the MonoTouch.Foundation.AddObserver(NSObject, NSString, NSKeyValueObservingOptions, IntPtr) to start observing changes and the MonoTouch.Foundation.RemoveObserver(NSObject, NSString) method to stop receiving notifications.

Related content

Requirements

Namespace: MonoTouch.Foundation
Assembly: monotouch (in monotouch.dll)
Assembly Versions: 0.0.0.0