3iX

Reliable $1 Web Hosting by 3iX

Tuesday, November 23, 2010

Unity3D - Syntax Differences in C# and Javascript

 

Unity3D - Syntax Differences in C# and Javascript

 

The purpose of this answer is to provide a single point of reference for the syntactical differences between C# and JS. It is mainly for people who have already made their decision as to which language to use, and might need to know the differences (for instance, to translate a script from one language to another).

 

Unity Script Directives

Unity has a number of Script Directives, for example, AddComponentMenu.

The syntax is:

// Javascript example
@script
AddComponentMenu ("Transform/Follow Transform")
class FollowTransform extends MonoBehaviour {
}  

// C# example:
[AddComponentMenu("Transform/Follow Transform")]
class FollowTransform : MonoBehaviour {
}

Type names

A couple of the basic types are spelt differently in pure Unity C#:

  • C#: bool, Javascript: boolean
  • C#: string, Javascript: String
However, if you include System in your C# script, you can also use .NET's String and Boolean class (note the upper-case):
using System;
String foo = "testing";
Boolean bar = false;

Variable declaration

Variable declaration is different, including access and type specification:

// C#: the type is always stated when declaring a variable:

public int myPublicInt = 1;      // a public var

int myPrivateInt = 2;            // **private** access is default, if access is unspecified

public GameObject myObj;         // a type is specified, but no value assigned

// Javascript - type specification is not necessary:

var myPublicInt = 1;             // **public** access is default, if unspecified

private var myPrivateInt = 2;    // a private var

var myObj : GameObject;          // a type is specified, but no value assigned (see below)



Variables with dynamic type resolution

In Javascript only, variables can have an unspecified type. This only occurs if you do not assign a value while declaring the variable. For example:

// Javascript:

var numBullets : int;  // statically typed (because type specified)

var numLivesLeft = 3;  // statically typed (because type is inferred from value assigned)

var player;            // dynamically typed (because neither a type or value is specified)

Performance is slower with dynamically typed variables, and you can run into casting problems.


Multi-dimensional array declaration not supported

Unity's Javascript doesn't support the syntax for declaring multi-dimensional built-in arrays. Eg:

// C#:

int[,] = new int[16,16];  // 16x16 2d int array

// Javascript:

// not possible!

You can of course nest arrays in Javascript, creating what is called a "jagged array", however - strangely enough - it's also possible to work with built-in 2d arrays in Javascript, providing 2d array originates from somewhere other than being explicitly declared in in your script. This means you can use a C# helper script, like this one on the wiki to declare 2D arrays, which you can then use in Javascript.

Character literals not supported

Unity's Javascript seems to be missing the syntax to declare character literals. This means you need to get them implicitly by referencing a character index from a string. For example:

// C#

char myChar = 'a';

// Javascript:

var myChar = "a"[0];  // implicitly retrieves the first character of the string "a"



Class declarations

You can define classes in Javascript, in a similar way to C#. Here's an example of a class which inherits from MonoBehaviour // Javascript example

class MyClass extends MonoBehaviour {

    var myVar = 1;

    function Start() {

Debug.Log("hello world!");

}

}  

// C# example:

class MyClass : MonoBehaviour {

    public int myVar = 1;

    void Start() {

Debug.Log("hello world!");

}

}

However in Javascript, if you're inheriting from MonoBehaviour, you don't need to write a class body at all (see the next section).

You can also write classes which do not inherit from anything, however you can't place scripts like this on Game Objects - you have to instantiate them with the 'new' keyword:

// Javascript example

class MyClass {

    var myVar = 1;

    // constructor:

public function MyClass() {

Debug.Log("hello world!");

}

}  

// C# example:

class MyClass{

    public int myVar = 1;

    // constructor:

public MyClass() {

Debug.Log("hello world!");

}

}

If you are inheriting from MonoBehaviour, you should not use constructors or destructors. Instead, use the Event handler functions "Start", "Awake" and "OnEnabled".

 


Implicit Class declarations

Unity's Javascript has a feature whereby if you do not declare any class body, it is automatically implemented for you. For example, a script which contains only variables and functions (and no explicit class declaration) is automatically implemented as:

// Your javascript is converted to (approximately)

class TheScriptName extends MonoBehaviour {

... your script here

}

This means that any Javascript script that you write without an explicit class body, automatically inherits from MonoBehaviour, and is therefore a component which can be attached to a GameObject (which is usually what you want!).


Limited interface support

While Unity's Javascript does support inheritance and interfaces, it has the very limiting caveat that you can either inherit your class from an existing class, or declare one interface. Eg:

// C#

class Apple : MonoBehaviour, ICollectable, IEatable, IThrowable { ... }

// Javascript - only one allowed:

class Apple extends CollectableObject { ... }

// or

class Apple extends IThrowable { ... }


Generics

The C# syntax supports "Generics" which allows you to use classes and methods which do not specifically declare a type. Instead, the type is passed as a parameter when calling the method or instantiating the class at runtime. These now work in both Unity and Unity iPhone (since v1.6).

.Net comes with some useful Generic classes such as the List and Dictionary, and Unity's own API has some generic functions which remove the need for some of the verbose casting which would otherwise be necessary in C#. For example:

// In Javascript, the "GetComponent" function returns an object, which is automatically cast by Javascript to the correct type

var someScript : ExampleScript = GetComponent(ExampleScript);

// In C#, without the Generic version of "GetComponent" we'd have to cast it ourselves (yuck):

ExampleScript someScript = (ExampleScript) GetComponent(typeof(ExampleScript));

// But instead, we can use the generic version provided by the Unity API, like this:

ExampleScript someScript = GetComponent<ExampleScript>();

For a more complete definition of Generics: MS Introduction to C# Generics


The Foreach keyword

C# Iterators use foreach instead of for. Also notice the variable declaration within the for/foreach statement. C# requires the type of the item contained in the list to be explicitly declared.

// Javascript

for (var item in someList) {

item.DoSomething();

}

// C#

foreach (ItemType item in someList)

{

item.DoSomething();

}


The New keyword

In Javascript, you can create a new instance of an object or struct without using the 'new' keyword. In C#, using "new" is mandatory.

// Javascript:

var myPosition = Vector3(0,0,0);

var myInstance = MyClass(); // creates a new instance of script "MyClass".

var myTex = Texture2D(128,128); // creates a new texture2d object.

// C#

Vector3 myPosition = new Vector3(0,0,0);

MyClass myInstance = new MyClass();

Texture2D myTex = new Texture2D(128,128);


Yield in Unity C# versus Unity Javascript

Although Unity's documentation does (briefly) cover the syntax differences in using Yield at Writing C# Scripts(Step 4), there is also a Unity Answer that covers How do I Use Yield in C#, which has a more detailed explanation. In addition, the answer by equalsequals has a link to a Coroutine Tutorial that is worth checking out.

Unity's Yield has additional capabilities over .NET C# Yield

The above paragraph covered the differences in Unity's C# versus Javascript syntax. However, I think that it's worth explaining that the behavior of Unity's Yield statement (in both C# and Javascript), has some additional features not in Microsoft's .Net C# behavior.

Basically, Unity has added the YieldInstruction (and child classes such as WaitForSeconds) to Yield. These classes give Yield the ability to temporarily pause the function, until a condition is met. If it has zero parameters, it pauses for a single frame. If it has a parameter of WaitForSeconds:

yield return new WaitForSeconds (2.0f); // pauses for 2 seconds.

then it pauses for some number of seconds. If the parameter is another Coroutine, then it pauses until that Coroutine finishes.

Yield only works this way inside a Coroutine. To start a Coroutine in C#, you use StartCoroutine, whereas it is automatically called in Javascript.

For a good explanation of how Coroutines and the main routine interact, see Duck's Answer


Casting

Javascript automatically casts from one type to another, where possible. For example, the "Instantiate" command returns a type of "Object":

// in Javascript, there's no need to cast the result of "Instantiate" provided the variable's type is declared:

var newObject : GameObject = Instantiate(sourceObject);

// in C#, both the variable and the result of instantiate must be declared:

GameObject foo = (GameObject) Instantiate(sourceObject); // C#

GameObject foo = Instantiate(sourceObject) as GameObject; // C# second version

Also, see Murcho's answer for more information about casting, including why you would want to use the second casting method listed.


Properties with Getters/Setters

In C#, it is possible to define special functions that can be accessed as if they were variables. For instance, I could say foo.someVar = "testing";, and under the hood, there are get and set functions which process the argument "testing" and store it internally. But - they could also do any other processing on it, for instance, capitalizing the first letter before storing it. So you're not just doing a variable assignment, you're calling a function that sets the variable, and it can do - whatever functions do.

I'm not going into the syntax here, this answer is long enough :) But here are two links:



MS: Using Properties, and C# Properties Tutorial.


Changing struct properties / by value vs by reference

This is actually a bit more than a syntactical difference but nevertheless fits here quite well:

The following code does work in JavaScript/UnityScript but not in C#:

transform.position.x = 3;

The reason is because transform.position really is not just a public variable but a property, so it's actually returned by a method call - and that happens "by value" for structs (Vector3 is a struct and not a class - for performance reasons). So, to achieve the same in C#, you have to write:

Vector3 pos = transform.position;

pos.x = 3;

transform.position = pos;


Function/Method definitions

First of all, terminology - Javascript uses the term "Function", while C# calls these "Methods". They mean the same thing, and most C# coders understand the term "Function".

Javascript functions are declared with the keyword function before the function name. C# Method declarations just use the return type, and the method name. The return type is often "void" for common Unity events. Javascript functions are public by default, and you can specify them as private if required. C# methods are private by default, and you can specify that they should be public if required.

In Javascript, you can omit the parameter types and the return type from the declaration, but it's also possible to explicitly specify these (which is sometimes necessary if you run into type ambiguity problems).

Javascript function examples:

// a common Unity monobehaviour event handler:

function Start () { ...function body here... }

// a private function:

private function TakeDamage (amount) {

energy -= amount;

}

// a public function with a return type.

// the paramter type is "Transform", and the return type is "int"

function GetDistanceTo (other : Transform) : int {

return (transform.position - other.position).magnitude;

}

And the equivalent C# methods examples:

// a common Unity monobehaviour event handler:

void Start() { ...function body here... }

// a private function:

void TakeDamage(int amount) {

energy -= amount;

}

// a public function with a return type.

// the parameter type is "Transform", and the return type is "int"

public int GetDistanceTo (Transform other) {

return (transform.position - other.position).magnitude;

}

 

Saturday, November 13, 2010

Unity 3d SQLite Database connection

C Sharp Script file to use wtih unity 3D. This one works with unity pro <= version 2.6 only free versions you can test but cannot build. And for Unity 3D 3 and above they don't support building for webplayer, standalone builds only work and you have to set standard .net 2.0 framework on build settings

dbAccess.cs


using UnityEngine;
using System;
using System.Collections;
using System.Data;
using Mono.Data.SqliteClient;

public class dbAccess : MonoBehaviour {
private string connection;
private IDbConnection dbcon;
private IDbCommand dbcmd;
private IDataReader reader;

// Use this for initialization
void Start () {

}

public void OpenDB(string p)
{
connection = "URI=file:" + p; // we set the connection to our database
dbcon = new SqliteConnection(connection);
dbcon.Open();
}

public void CloseDB(){
reader.Close(); // clean everything up
   reader = null;
   dbcmd.Dispose();
   dbcmd = null;
   dbcon.Close();
   dbcon = null;
}

IDataReader BasicQuery(string query){ // run a baic Sqlite query
dbcmd = dbcon.CreateCommand(); // create empty command
dbcmd.CommandText = query; // fill the command
reader = dbcmd.ExecuteReader(); // execute command which returns a reader
return reader; // return the reader

}


int CreateTable(string name,string[] col, string[] colType){ // Create a table, name, column array, column type array
string query;
query  = "CREATE TABLE " + name + "(" + col[0] + " " + colType[0];
for(var i=1; i
query += ", " + col[i] + " " + colType[i];
}
query += ")";
try{
dbcmd = dbcon.CreateCommand(); // create empty command
dbcmd.CommandText = query; // fill the command
reader = dbcmd.ExecuteReader(); // execute command which returns a reader
}
catch(Exception e){

Debug.Log(e);
return 0;
}
return 1;
}

int InsertIntoSingle(string tableName, string colName , string value ){ // single insert
string query;
query = "INSERT INTO " + tableName + "(" + colName + ") " + "VALUES (" + value + ")";
try
{
dbcmd = dbcon.CreateCommand(); // create empty command
dbcmd.CommandText = query; // fill the command
reader = dbcmd.ExecuteReader(); // execute command which returns a reader
}
catch(Exception e){

Debug.Log(e);
return 0;
}
return 1;
}

int InsertIntoSpecific(string tableName, string[] col, string[] values){ // Specific insert with col and values
string query;
query = "INSERT INTO " + tableName + "(" + col[0];
for(int i=1; i
query += ", " + col[i];
}
query += ") VALUES (" + values[0];
for(int i=1; i
query += ", " + values[i];
}
query += ")";
try
{
dbcmd = dbcon.CreateCommand();
dbcmd.CommandText = query;
reader = dbcmd.ExecuteReader();
}
catch(Exception e){

Debug.Log(e);
return 0;
}
return 1;
}

int InsertInto(string tableName , string[] values ){ // basic Insert with just values
string query;
query = "INSERT INTO " + tableName + " VALUES (" + values[0];
for(int i=1; i
query += ", " + values[i];
}
query += ")";
try
{
dbcmd = dbcon.CreateCommand();
dbcmd.CommandText = query;
reader = dbcmd.ExecuteReader();
}
catch(Exception e){

Debug.Log(e);
return 0;
}
return 1;
}

public string[] SingleSelectWhere(string tableName , string itemToSelect,string wCol,string wPar, string wValue){ // Selects a single Item
string query;
query = "SELECT " + itemToSelect + " FROM " + tableName + " WHERE " + wCol + wPar + wValue;
dbcmd = dbcon.CreateCommand();
dbcmd.CommandText = query;
reader = dbcmd.ExecuteReader();
string[] readArray = new string[reader.RecordsAffected];
int i=0;
while(reader.Read()){
readArray[i]=reader.GetString(0); // Fill array with all matches
i++;
}
return readArray; // return matches
}





// Update is called once per frame
void Update () {

}
}

The following few dlls have to be added inside Assets/Plugins folder

Mono.Data.Sqlite.dll
Mono.Data.SqliteClient.dll
MySql.Data.dll
sqlite3.dll
System.Data.dll

Tuesday, November 9, 2010

IOS Executing Code in the Background


Applications linked against iOS 4 and later are automatically assumed to support multitasking and to implement the appropriate methods to handle transitions to the background state. However, work is still required to ensure that your application transitions smoothly between the foreground and background.

Determining Whether Multitasking Support is Available

The ability to run background tasks is not supported on all iOS-based devices. If a device is not running iOS 4 and later, or if the hardware is not capable of running applications in the background, the system reverts to the previously defined behavior for handling applications. Specifically, when an application is quit, its application delegate receives an applicationWillTerminate: message, after which the application is terminated and purged from memory.
Applications should be prepared to handle situations where multitasking is not available. If your code supports background tasks but is able to run without them, you can use the multitaskingSupported property of the UIDevice class to determine whether multitasking is available. Of course, if your application supports versions of the system earlier than iOS 4, you should always check the availability of this property before accessing it, as shown in Listing 4-1.

Listing 4-1  Checking for background support on earlier versions of iOS
UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
backgroundSupported = device.multitaskingSupported;

Declaring the Background Tasks You Support

Support for some types of background execution must be declared in advance by the application that uses them. An application does this by including the UIBackgroundModes key in its Info.plist file. This key identifies which background tasks your application supports. Its value is an array that contains one or more strings with the following values:
  • audio - The application plays audible content to the user while in the background.
  • location - The application keeps users informed of their location, even while running in the background.
  • voip - The application provides the ability for the user to make phone calls using an Internet connection.
Each of the preceding values lets the system know that your application should be woken up at appropriate times to respond to relevant events. For example, an application that begins playing music and then moves to the background still needs execution time to fill the audio output buffers. Including the audio key tells the system frameworks that they should continue playing and make the necessary callbacks to the application at appropriate intervals. If the application did not include this key, any audio being played by the application would stop when the application moved to the background.
In addition to the preceding keys, iOS provides two other ways to do work in the background:
  • Applications can ask the system for extra time to complete a given task.
  • Applications can schedule local notifications to be delivered at a predetermined time.

Supporting Background State Transitions

Supporting the background state transition is part of the fundamental architecture for applications in iOS 4 and later. Although technically the only thing you have to do to support this capability is link against iOS 4 and later, properly supporting it requires some additional work. Specifically, your application delegate should implement the following methods and implement appropriate behaviors in each of them:
These methods are called at key times during your application’s execution to let you know when your application is changing states. Although many of these methods have been present in iOS applications for some time, their purpose was more narrowly defined previously. Applications implementing these methods now must use them to address some additional behaviors that are needed to operate safely in the background. For example, an application that went into the background and purged from memory might be relaunched and expected to continue operating from where it last was. Thus, your application’s application:didFinishLaunchingWithOptions: method may now need to check and see what additional launch information is available and use that information plus any saved state to restore the application’s user interface.
For information and guidance on how to implement the methods in your application, see “Understanding an Application’s States and Transitions.”

Being a Responsible, Multitasking-Aware Application

Applications that run in the background are more limited in what they can do than a foreground application. And even if your application does not run in the background, there are are certain guidelines you should follow when implementing your application.
  • Do not make any OpenGL ES calls from your code. You must not create an EAGLContext object or issue any OpenGL ES drawing commands of any kind. Using these calls will cause your application to be terminated immediately.
  • Cancel any Bonjour-related services before being suspended. When your application moves to the background, and before it is suspended, it should unregister from Bonjour and close listening sockets associated with any network services. A suspended application cannot respond to incoming service requests anyway. Closing out those services prevents them from appearing to be available when they actually are not. If you do not close out Bonjour services yourself, the system closes out those services automatically when your application is suspended.
  • Be prepared to handle connection failures in your network-based sockets. The system may tear down socket connections while your application is suspended for any number of reasons. As long as your socket-based code is prepared for other types of network failures, such as a lost signal or network transition, this should not lead to any unusual problems. When your application resumes, if it encounters a failure upon using a socket, simply reestablish the connection.
  • Save your application state before moving to the background. During low-memory conditions, background applications are purged from memory to free up space. Suspended applications are purged first, and no notice is given to the application before it is purged. As a result, before moving to the background, an application should always save enough state information to reconstitute itself later if necessary. Restoring your application to its previous state also provides consistency for the user, who will see a snapshot of your application’s main window briefly when it is relaunched.
  • Release any unneeded memory when moving to the background. Background applications must maintain enough state information to be able to resume operation quickly when they move back to the foreground. But if there are objects or relatively large memory blocks that you no longer need (such as unused images), you should consider releasing that memory when moving to the background.
  • Stop using shared system resources before being suspended. Applications that interact with shared system resources such as Address Book need to stop using those resources before being suspended. Priority over such resources always goes to the foreground application. At suspend time, if an application is found to be using a shared resource, it will be terminated instead.
  • Avoid updating your windows and views. While in the background, your application’s windows and views are not visible, so you should not try to update them. Although creating and manipulating window and view objects in the background will not cause your application to be terminated, this work should be postponed until your application moves to the foreground.
  • Respond to connect and disconnect notifications for external accessories. For applications that communicate with external accessories, the system automatically sends a disconnection notification when the application moves to the background. The application must register for this notification and use it to close out the current accessory session. When the application moves back to the foreground, a matching connection notification is sent giving the application a chance to reconnect.
    • Clean up resources for active alerts when moving to the background. In order to preserve context when switching between applications, the system does not automatically dismiss action sheets (UIActionSheet) or alert views (UIAlertView) when your application moves to the background. (For applications linked against iOS 3.x and earlier, action sheets and alerts are still dismissed at quit time so that your application’s cancellation handler has a chance to run.) It is up to you to provide the appropriate cleanup behavior prior to moving to the background. For example, you might want to cancel the action sheet or alert view programmatically or save enough contextual information to restore the view later (in cases where your application is terminated).
    • Remove sensitive information from views before moving to the background. When an application transitions to the background, the system takes a snapshot of the application’s main window, which it then presents briefly when transitioning your application back to the foreground. Before returning from your applicationDidEnterBackground: method, you should hide or obscure passwords and other sensitive personal information that might be captured as part of the snapshot.
    • Do minimal work while running in the background. The execution time given to background applications is more constrained than the amount of time given to the foreground application. If your application plays background audio or monitors location changes, you should focus on that task only and defer any nonessential tasks until later. Applications that spend too much time executing in the background can be throttled back further by the system or terminated altogether.
    If you are implementing a background audio application, or any other type of application that is not suspended while in the background, your application responds to incoming messages in the usual way. In other words, the system may notify your application of low-memory warnings when they occur. And in situations where the system needs to terminate applications to free up even more memory, the application calls its delegate’sapplicationWillTerminate: method to perform any final tasks before exiting.

    Initiating Background Tasks

    The steps for initiating a background task depend entirely on the task at hand. Some tasks must be initiated explicitly, while others happen in a more automatic way for your application. The following sections provide guidance and examples on how to initiate each type of background task.

    Completing a Long-Running Task in the Background

    Any time before it is suspended, an application can call the beginBackgroundTaskWithExpirationHandler: method to ask the system for extra time to complete some long-running task in the background. If the request is granted, and if the application goes into the background while the task is in progress, the system lets the application run for an additional amount of time instead of suspending it. (The amount of time left for the application to run is available in the backgroundTimeRemaining property of the UIApplication object.)
    You can use background tasks to ensure that important but potentially long-running operations do not end abruptly when the user quits the application. For example, you might use this technique to finish downloading an important file from a network server. There are a couple of design patterns you can use to initiate such tasks:
    • Wrap any long-running critical tasks with beginBackgroundTaskWithExpirationHandler: and endBackgroundTask: calls. This protects those tasks in situations where your application is suddenly moved to the background.
    • Wait for your application delegate’s applicationDidEnterBackground: method to be called and start one or more tasks then.
    All calls to the beginBackgroundTaskWithExpirationHandler: method must be balanced with a corresponding call to the endBackgroundTask:method. The endBackgroundTask: method lets the system know that the desired task is complete and that the application can now be suspended. Because applications running in the background have a limited amount of execution time, calling this method is also critical to avoid the termination of your application. (You can always check the value in the backgroundTimeRemaining property to see how much time is left.) An application with outstanding background tasks is terminated rather than suspended when its time limit expires. You can also provide an expiration handler for each task and call the endBackgroundTask: from there.
    An application may have any number of background tasks running at the same time. Each time you start a task, thebeginBackgroundTaskWithExpirationHandler: method returns a unique identifier for the task. You must pass this same identifier to theendBackgroundTask: method when it comes time to end the task.
    Listing 4-2 shows how to start a long-running task when your application transitions to the background. In this example, the request to start a background task includes an expiration handler just in case the task takes too long. The task itself is then submitted to a dispatch queue for asynchronous execution so that the applicationDidEnterBackground: method can return normally. The use of blocks simplifies the code needed to maintain references to any important variables, such as the background task identifier. The bgTask variable is a member variable of the class that stores a pointer to the current background task identifier.
    Listing 4-2  Starting a background task at quit time
    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
    UIApplication*    app = [UIApplication sharedApplication];
    bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
    }];
    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Do the work associated with the task.
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
    });
    }
    In your own expiration handlers, you can include additional code needed to close out your task. However, any code you include should not take long to execute. By the time your expiration handler is called, your application is already very close to its time limit. Doing anything other than clean up your state information and exiting could cause your application to be terminated.

    Scheduling the Delivery of Local Notifications

    The UILocalNotification class in UIKit provides a way to schedule the delivery of push notifications locally. Unlike push notifications, which require setting up a remote server, local notifications are scheduled by your application and executed on the current device. You can use this capability to achieve the following behaviors:
    • A time-based application can ask the system to post an alert at a specific time in the future. For example, an alarm clock application would use this to implement alarms.
    • An application running in the background can post a local notification to get the user’s attention.
    To schedule the delivery of a local notification, create an instance of the UILocalNotification class, configure it, and schedule it using the methods of the UIApplication class. The local notification object contains information about the type of notification to deliver (sound, alert, or badge) and the time (when applicable) at which to deliver it. The methods of the UIApplication class provide options for delivering notifications immediately or at the scheduled time.
    Listing 4-3 shows an example that schedules a single alarm using a date and time that is set by the user. This example supports only one alarm at a time and therefore cancels the previous alarm before scheduling a new one. Your own applications can schedule up to 128 simultaneous notifications, any of which can be configured to repeat at a specified interval. The alarm itself consists of a sound file and an alert box that is played if the application is not running or is in the background when the alarm fires. If the application is active and therefore running in the foreground, the application delegate’s application:didReceiveLocalNotification: method is called instead.
    Listing 4-3  Scheduling an alarm notification
    - (void)scheduleAlarmForDate:(NSDate*)theDate
    {
    UIApplication* app = [UIApplication sharedApplication];
    NSArray*    oldNotifications = [app scheduledLocalNotifications];
    // Clear out the old notification before scheduling a new one.
    if ([oldNotifications count] > 0)
    [app cancelAllLocalNotifications];
    // Create a new notification
    UILocalNotification* alarm = [[[UILocalNotification alloc] init] autorelease];
    if (alarm)
    {
    alarm.fireDate = theDate;
    alarm.timeZone = [NSTimeZone defaultTimeZone];
    alarm.repeatInterval = 0;
    alarm.soundName = @"alarmsound.caf";
    alarm.alertBody = @"Time to wake up!";
    [app scheduleLocalNotification:alarm];
    }
    }
    Sound files used with local notifications have the same requirements as those used for push notifications. Custom sound files must be located inside your application’s main bundle and support one of the following formats: linear PCM, MA4, uLaw, or aLaw. You can also specify a sound name ofdefault to play the default alert sound for the device. When the notification is sent and the sound is played, the system also triggers a vibration on devices that support it.

    Receiving Location Events in the Background

    Applications that use location data to track the user’s position now have the option to do so while running in the background. In fact, applications now have more options for receiving location events:
    • Applications can register for significant location changes only. (Recommended) The significant-change location service is available in iOS 4 and later for devices with a cellular radio. It offers a low-power way to receive location data and is highly recommended. New location updates are provided only when the user’s position changes significantly. If the application is suspended while running this service, new location updates will cause the application to be woken up in the background to handle them. Similarly, if the application is terminated while running this service, the system relaunches the application automatically when new location data becomes available.
    • Applications can continue to use the standard location services. These services are available in all versions of iOS and provide continuous updates while the application is running in the foreground or background. However, if the application is suspended or terminated, new location events do not cause the application to be woken up or relaunched.
    • An application can declare itself as a continuous background location application. An application that needs the regular location updates offered by the standard location services may declare itself as a continuous background application. It does this by including theUIBackgroundModes key in its Info.plist file and setting the value of this key to an array containing the location string. If an application with this key is running location services when it enters the background, it is not suspended by the system. Instead, it is allowed to continue running so that it may perform location-related tasks in the background.
    Regardless of which option you pick, running location services continuously in the background requires enabling the appropriate radio hardware and keeping it active, which can require a significant amount of battery power. If your application does not require precise location information, the best solution is to use the significant location service. You start this service by calling the startMonitoringSignificantLocationChanges method ofCLLocationManager. This service gives the system more freedom to power down the radio hardware and send notifications only when significant location changes are detected. For example, the location manager typically waits until the cell radio detects and starts using a new cell tower for communication.
    Another advantage of the significant location service is its ability to wake up and relaunch your application. If a location event arrives while the application is suspended, the application is woken up and given a small amount of time to handle the event. If the application is terminated and a new event arrives, the application is relaunched. Upon relaunch, the options dictionary passed to the application:didFinishLaunchingWithOptions:method contains the UIApplicationLaunchOptionsLocationKey key to let the application know that a new location event is available. The application can then restart location services and receive the new event.
    For applications that need more precise location data at regular intervals, such as navigation applications, you may need to declare the application as a continuous background application. This option is the least desirable option because it increases power usage considerably. Not only does the application consume power by running in the background, it must also keep location services active, which also consumes power. As a result, you should avoid this option whenever possible.
    Regardless of whether you use the significant-change location service or the standard location services, the process for actually receiving location updates is unchanged. After starting location services, the locationManager:didUpdateToLocation:fromLocation: method of your location manager delegate is called whenever an event arrives. Of course, applications that run continuously in the background may also want to adjust the implementation of this method to do less work while in the background. For example, you might want to update the application’s views only while the application is in the foreground

    Playing Background Audio

    Applications that play audio can continue playing that audio while in the background. To indicate that your application plays background audio, include the UIBackgroundModes key to its Info.plist file. The value for this key is an array containing the audio string. When this key is present, the system’s audio frameworks automatically prevent your application from being suspended when it moves to the background. Your application continues to run in the background as long as it is playing audio. However, if this key is not present when the application moves to the background, or if your application stops playing audio while in the background, your application is suspended.
    You can use any of the system audio frameworks to initiate the playback of background audio and the process for using those frameworks is unchanged. Because your application is not suspended while playing audio, the audio callbacks operate normally while your application is in the background. While running in the background, your application should limit itself to doing only the work necessary to provide audio data for playback. Thus, a streaming audio application would download any new data from its server and push the current audio samples out for playback.

    Implementing a VoIP Application

    Voice over Internet Protocol (VoIP) application allows the user to make phone calls using an Internet connection instead of the device’s cellular service. Such an application needs to maintain a persistent network connection to its associated service. Among other things, this persistent connection allows the application to receive and respond to incoming calls. Rather than keep a VoIP application awake so that it can maintain its network connection, the system provides facilities for managing the sockets associated with that connection while the application is suspended.
    To configure a VoIP application, you must do the following:
    1. Add the UIBackgroundModes key to your application’s Info.plist file. Set the value of this key to an array that includes the voip string.
    2. Configure your socket for VoIP usage.
    3. Before moving to the background, call the setKeepAliveTimeout:handler: method to specify the frequency at which your application must be woken to maintain your service.
    4. Configure your audio session to handle transitions to and from active use.
    Including the voip value in the UIBackgroundModes key lets the system know that it should allow the application to run in the background as needed to manage its network sockets. An application with this key is also relaunched in the background immediately after system boot to ensure that the VoIP services are always available.
    Most VoIP applications also need to be configured as background audio applications in order to process audio while in the background. To do so, you must add both the audio and voip values to the UIBackgroundModes key. Otherwise, there are no changes to how you use the audio frameworks to play and record audio.

    Configuring Sockets for VoIP Usage

    In order for your application to maintain a persistent connection while it is in the background, you must configure the sockets used to communicate with your VoIP service. In iOS, most sockets are managed using higher-level constructs such as streams. As a result, configuration of a socket to support VoIP occurs through the higher-level interfaces. The only thing you have to do beyond the normal configuration is add a special key that tags the interface as being used for a VoIP service. Table 4-1 lists the interfaces that you can configure for VoIP usage and the keys you assign.
    Table 4-1  Configuring stream interfaces for VoIP usage
    Interface
    Configuration
    For Cocoa streams, use the setProperty:forKey: method to add the NSStreamNetworkServiceType property to the stream. The value of this property should be set to NSStreamNetworkServiceTypeVoIP.
    When using the URL loading system, use the setNetworkServiceType: method of your NSMutableURLRequest object to set the network service type of the request. The service type should be set to NSURLNetworkServiceTypeVoIP.
    For Core Foundation streams, use the CFReadStreamSetProperty or CFWriteStreamSetProperty function to add thekCFStreamNetworkServiceType property to the stream. The value for this property should be set tokCFStreamNetworkServiceTypeVoIP.
    When you configure a stream for VoIP usage, the system takes over management of the underlying socket while your application is suspended. This handoff to the system is transparent to your application. If new data arrives while your application is suspended, the system wakes up your application so that it can process the data. In the case of an incoming phone call, your application would typically alert the user immediately using a local notification. For other noncritical data, or if the user ignores the call, the system returns your application to the suspended state when it finishes processing the data.
    Because VoIP applications need to stay running in order to receive incoming calls, the system automatically relaunches the application if it exits with a nonzero exit code. (This could happen in cases where there is memory pressure and your application is terminated as a result.) However, the system does not maintain your socket connections between different launches of your application. Therefore, at launch time, your application always needs to recreate those connections from scratch.
    For more information about configuring Cocoa stream objects, see Stream Programming Guide. For information about using URL requests, see URL Loading System Programming Guide. And for information about configuring streams using the CFNetwork interfaces, see CFNetwork Programming Guide.

    Installing a Keep-Alive Handler

    To prevent the loss of its connection, a VoIP application typically needs to wake up periodically and check in with its server. To facilitate this behavior, iOS lets you install a special handler using the setKeepAliveTimeout:handler: method of UIApplication. You typically install this handler when moving to the background. Once installed, the system calls your handler at least once before the timeout interval expires, waking up your application as needed to do so. You can use this handler to check in with your VoIP service and perform any other relevant housekeeping chores.
    Your keep-alive handler executes in the background and must return as quickly as possible. Handlers are given a maximum of 30 seconds to perform any needed tasks and return. If a handler has not returned after 30 seconds, the system terminates the application.
    When installing your handler, you should specify the largest timeout value that is practical for your needs. The minimum allowable interval for running your handler is 600 seconds and attempting to install a handler with a smaller timeout value will fail. Although the system promises to call your handler block before the timeout value expires, it does not guarantee the exact call time. To improve battery life, the system typically groups the execution of your handler with other periodic system tasks, thereby processing all tasks in one quick burst. As a result, your handler code must be prepared to run earlier than the actual timeout period you specified.

    Configuring Your Application’s Audio Session

    The audio session for a VoIP application must be configured properly to ensure the application works smoothly with other audio-based applications. Because audio playback and recording for a VoIP application are not used all the time, it is especially important that you create and configure your application’s audio session only when it is needed to handle a call or provide notifications to the user and release it at other times. This gives other audio applications the opportunity to play their audio the rest of the time.

News