Monday, July 12, 2010

Playing Sound with button clicks - Vuvuzela App

In this article, we will doing an app that plays sounds when you click on button. Many hots apps that have been downloaded just leverage upon this simple idea. Get a funny/interesting sound, press a button (helps if you have an image for the button) and play the sound.

In this article, let's have an app that plays cute baby sound whenever a user clicks on a button. Create a new view-based application in xcode, then design a UI similar to the below in InterfaceBuilder. Take note that the images are actually buttons, where you just have to specify the image property of the button. The rest of the controls are basically labels.


In my app, I have four buttons. Of course one will do if that is a really cool sound, for eg. vuvuzela. Copy the below code as your ViewController.h file

#import <UIKit/UIKit.h>
#include <AudioToolbox/AudioToolbox.h>

@interface SysSoundViewController : UIViewController {
CFURLRef soundFileURLRef;
SystemSoundID soundFileObject;
}

@property (readwrite) CFURLRef soundFileURLRef;
@property (readonly) SystemSoundID soundFileObject;

- (IBAction) playASound;
- (IBAction) vibrate;
@end


Explanation:
We declare a CFURLRef which is a reference to a object representing access to a URL. It is useful as long as the resource you are accessing can be done via a URL. This CSURL object will later hold the URL to our sound files.

CFURLRef soundFileURLRef;

SystemSoundID represents a System Sound object.

SystemSoundID soundFileObject;

We next declare two Actions for linking to our buttons later on. One to play a sound, the other, to vibrate the phone.
- (IBAction) playASound;
- (IBAction) vibrate;

Copy the following code next for the ViewController.m file.

#import "SysSoundViewController.h"
@implementation SysSoundViewController

@synthesize soundFileURLRef;
@synthesize soundFileObject;

CFBundleRef mainBundle;

- (void) viewDidLoad {
[super viewDidLoad];
// Get the main bundle for the app
mainBundle = CFBundleGetMainBundle ();
}

// Respond to a tap on the System Sound button
- (IBAction) playASound {
// Get the URL to the sound file to play
soundFileURLRef  = CFBundleCopyResourceURL (mainBundle,CFSTR ("a"),CFSTR("wav"),NULL);
// Create a system sound object representing the sound file
AudioServicesCreateSystemSoundID (soundFileURLRef, &soundFileObject);
AudioServicesPlaySystemSound (self.soundFileObject);
}

// Respond to a tap on the Vibrate button
- (IBAction) vibrate {
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}

- (void) dealloc {
[super dealloc];
AudioServicesDisposeSystemSoundID (self.soundFileObject);
CFRelease (soundFileURLRef);
}
@end


Explanation:

The CFBundle allows you to use a folder hierachy called a bundle to organize and locate serveral kinds of resources like images, sounds or executable code. In our case, it represents the folder hierachy we have in the 'Resources' folder. Essentially, it provides us access to our Resources folder.

CFBundleRef mainBundle;

The viewDidLoad is the method that is called whenever the View loads. In it, we call the viewDidLoad of the parent class i.e. UIView.
- (void) viewDidLoad {
[super viewDidLoad];
Returns the application's main bundle. Or folder.
// Get the main bundle for the app
mainBundle = CFBundleGetMainBundle ();
}

Action linked to button.

// Respond to a tap on the System Sound button
- (IBAction) playASound {

CFBundleCopyResourceURL returns the location of the resource of name "a" and type "wav" from the mainbundle (Resource folder). Of course ensure that you have a “a.wav” audio file under ‘Resources’.

// Get the URL to the sound file to play
soundFileURLRef  = CFBundleCopyResourceURL (mainBundle,CFSTR ("a"),CFSTR("wav"),NULL);
AudioServicesCreateSystemSoundID creates a system sound object from the specified URL (first argument) and outputs it to the &soundFileObject. Notice that there is a & before soundFileObject. What that means is that we are passing the soundFileObject object reference to the method, such that when the method returns, it actually refers to a initialized soundFileObject.
// Create a system sound object representing the sound file
AudioServicesCreateSystemSoundID (soundFileURLRef, &soundFileObject);
Finally, AudioServicesPlaySystemSound plays a short system sound of 30 secs or less. 'self' simply means 'this'. The current object's soundFileObject.
AudioServicesPlaySystemSound (self.soundFileObject);
}

For this particular Action, we can the same method AudioServicesPlaySystemSound but the argument passed is different. When we provide the kSystemSoundID_Vibrate argument to it, it will invoke a brief vibration.

// Respond to a tap on the Vibrate button
- (IBAction) vibrate {
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}

Releases and disposes of the soundFile and soundFileURL objects.
- (void) dealloc {
[super dealloc];
AudioServicesDisposeSystemSoundID (self.soundFileObject);
CFRelease (soundFileURLRef);
}
 
Ensure that you link the buttons to the Actions as described in earlier tutorials and soon, you are on your way to doing your own vuvuzela app!

Sunday, July 11, 2010

Make your own Vuvuzela app

iPhone Screenshot 2

It’s an app that’s been downloaded 5 million times. So what’s so special about it? Other similar examples are the iFart app.
Essentially, both apps are just buttons with an image that plays a sound when clicked. So how hard can it be?

Will go through how to play an audio file soon. And you can be on your way to doing your own vuvuzela app.

Saturday, July 10, 2010

Making the keyboard disappear - Easy Loan Calculator Part 4

How do we make the keyboard disappear?

Surprisingly, the return/done key does not allow us to close the keyboard.

What we aim to achieve to do here is whenever the user clicks outside of any textbox, the key board will disappear. How do we do that?

In Interface Builder, create a button and stretch it over the entire screen. It should cover the entire screen. Go to Layout -> Send to back. The button should be send to the back.



Hence, whenever a user clicks outside the textbox, she is actually clicking on the background button.

Remember that we have actually declared an Action in the .h file.

-(IBAction) bgTouched:(id) sender;


We have also implemented it in the .m file. 



-(IBAction) bgTouched:(id) sender{
[tbxLoanAmount resignFirstResponder];
[annualInterestRate resignFirstResponder];
[noOfYears resignFirstResponder];
}

What we are doing is resigning control of all the textboxes whenever the background button is clicked. This is done via calling the textbox resignFirstResponder instance method.

Last by not least, in Interface Builder, connect the background button to the bgTouched Action and your Easy Loan Calculator is finally complete! Yes after four parts!!

Press Command -R to try.

Feel free to give comments.

Friday, July 9, 2010

Using Interface Builder to connect Outlets/Actions - Easy Loan Calculator Part 3

Essentially, we have implemented all the codes. In summary, we have declared Outlets which are references to our UIControls and Actions, which are events which we be triggered when we click on buttons.

Now we need to link the Outlets to the UIControls that we have designed in our xib file. 
Apple enforces a View-Controller-Model. Which is essentially keeping the UI layer and the business logic layer separate. Advantages are that we can change either layer without affecting much the other layer. i.e. if i were to change my UI drastically, my business logic layer can still link to the new UI with some re-linking.

Now it is this linking that we are going to do now. Linking the text boxes and labels to the Outlets we have declared earlier. (They are called IBOutlet because IB - Interface Builder)

In Interface Builder, you have these window with three icons in it. The view icon just opens your View. Ignore First Responder for now. 

Click on File's owner. Press and hold the Control key. Mouse click from File's owner to over the textbox. You should see a black box with drop down values of all the Outlets of textbox type that you have declared earlier.  See below. Click on the Outlet which should correspond to that textbox. You have just linked your Outlet to the textbox.


Continue for the rest of the text boxes and labels. Having done that, we now proceed to link the button to the Action that we have implemented. i.e. link the Calculate button to the Calculate method.

Click on the button. Press and hold the Control key, and drag and hold to File's Owner. A black box with drop down values of the Events should appear. Select the correct event. In this case, we select the btnCalculate action.
You can think of Events or Actions as the same thing. 





There you go, your Outlets and Actions are all properly linked. Just ensure that you save all your files with command-S. Build and Run with command-R and the iPhone simulator should appear with your loan application. =)




So you learned the important lesson of Outlets and Actions through this exercise. Essentially, its all about receiving/sending user input (Outlets), and event handling with buttons (Actions).

With this, you can go on and build many many other applications.

Now as you test your application, a terrible thing happens. Your keyboard does not go away! Shocking! isn't this intuitive that the keyboard should go away? How do we make it go away?

We will touch on that in the next article.

Objective C - Convert string to double and double to string Part 2 - Filler


Before we go on to part 3, let me stop to pause for an important part of the code and zoom in a little more. For in the code, we have done something important, converting double into a string, and string into a double.

Now i initially thought that a simple google search would return me the result but to my horror...it doesn't! Especially for the double to format to 2 dp and become a string.

So here goes...

double loanAmount = [tbxLoanAmount.text doubleValue];

Remember the above code? Its to the equivalent of double d = Convert.ToDouble(tbx.Text) in C#. Over here, we are calling the doubleValue method of the String (or rather NSString - NS = NextStep) class to convert the text box Text property into a double.

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:2];
We now create the NumberFormatter object. Again its prefixxed with NS - NextStep. This object will format our 1.234566 into a nice 1.23 format. Of course you can format to percentages as well. There are also other formatters like date formatters.

NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];

We create the NumberFormatter object here. In short, we are doing a NumberFormatter nf = new NumberFormatter() here. [NSNumberFormatter alloc] is for allocating memory to hold this object. init - initialization. You will see [[Object alloc] init] very frequently.

NSNumber *n1 = [NSNumber numberWithDouble:paymentAmt];

Next, convert the double into a NSNumber type with the above code. Again, in C#, it will be NSNumber n1 = NSNumber.numberWithDouble(payment); Yea, its a static method.



 NSString *paymentAmtString = [numberFormatter stringFromNumber:n1];
Finally, using the numberFormatter object, which takes in a NSNumber argument, we finally convert our double to a String. Which we can assign to a text box Text property as per below.

monthlyPayment.text = paymentAmtString;

So in summary, double -> NSNumber -> NSNumberFormatter -> NSString.

Unbelieveable right, the amount of work you need to convert a formatted double into a String.
Yea, still more unbelievable things to come.

Outlets and Actions - Easy Loan Calculator Part 2

Ok, let's go on to implement the codes, the nuts and bolts of the calculator. In summary, we have to drag drop labels, textboxes to receive user input, some buttons to trigger the execution of the program, code the formula for the loan, and out put the result to labels again. Let's begin.

Under Resources, click on EasyLoanCalculatorViewController.xib file to open Interface Builder.
You will see a blank view. From the Library window, (you can open the Library from Tools -> Library) you can select your UI controls to the view. Its essentially like toolbox in visual studio.

So carry on and design your UI till it resembles something like the below. Ignore the picture of the percetage sign at the end.


In the process, you would have dragged and dropped several labels, text boxes, and buttons.

Next, let's type out the code for the EasyLoanCalculatorViewController.h file. The code is listed below.




#import

@interface EasyLoanCalculatorViewController : UIViewController {
IBOutlet UITextField *tbxLoanAmount;
IBOutlet UITextField *annualInterestRate;
IBOutlet UITextField *noOfYears;
IBOutlet UILabel *monthlyPayment;
IBOutlet UILabel *totalInterest;
IBOutlet UILabel *totalPayment;
}

@property (nonatomic,retain) UITextField *tbxLoanAmount;
@property (nonatomic,retain) UITextField *annualInterestRate;
@property (nonatomic,retain) UITextField *noOfYears;
@property (nonatomic,retain) UILabel *monthlyPayment;
@property (nonatomic,retain) UILabel *totalInterest;
@property (nonatomic,retain) UILabel *totalPayment;


-(IBAction) bgTouched:(id) sender;
-(IBAction) btnCalculate:(id) sender;

@end



Explanation of the codes. 

#import 

Import the UIKit framework. There are many other frameworks you can import like the Accelerometer, the MapKit and many others which we will go through in future tutorials.

@interface EasyLoanCalculator3ViewController : UIViewController {

Declare an interface EasyLoanCalculator3ViewController that inherits from UIViewController.





IBOutlet UITextField *tbxLoanAmount;
IBOutlet UITextField *annualInterestRate;
IBOutlet UITextField *noOfYears;
IBOutlet UILabel *monthlyPayment;
IBOutlet UILabel *totalInterest;
IBOutlet UILabel *totalPayment;
}


Declare the UIControls that you are to use in the xib file. These are what we have dragged and dropped previously. These are also called Outlets. Outlets are declarations of UIControls where we take in or out put data from/to user. Btw, you need to declare these variables with a * which means that there are object references. Don't understand? Just do it first. Will slowing understand later.

@property (nonatomic,retain) UITextField *tbxLoanAmount;
@property (nonatomic,retain) UITextField *annualInterestRate;
@property (nonatomic,retain) UITextField *noOfYears;
@property (nonatomic,retain) UILabel *monthlyPayment;
@property (nonatomic,retain) UILabel *totalInterest;
@property (nonatomic,retain) UILabel *totalPayment;

Set these UIControls as properties. Nonatomic refers to that there can be multiple threads running at the same time. 

-(IBAction) bgTouched:(id) sender;
-(IBAction) btnCalculate:(id) sender;

These are Actions. Typically, we use buttons to activate actions. We have to code these actions later on in the .m file. Here we have two actions. Just concentrate on btnCalculate for now. It is used for the calculation of the loan formula later on.

@end

I won't even comment on this. Next up, the .m file. Find the code below.





#import "EasyLoanCalculatorViewController.h"

@implementation EasyLoanCalculator3ViewController

@synthesize tbxLoanAmount;
@synthesize annualInterestRate;
@synthesize noOfYears;
@synthesize monthlyPayment;
@synthesize totalInterest;
@synthesize totalPayment;

-(IBAction) bgTouched:(id) sender{
[tbxLoanAmount resignFirstResponder];
[annualInterestRate resignFirstResponder];
[noOfYears resignFirstResponder];
}

-(IBAction) btnCalculate:(id) sender{
double loanAmount = [tbxLoanAmount.text doubleValue];
double intRate = [annualInterestRate.text doubleValue];
double years = [noOfYears.text doubleValue];
double r = intRate/1200; // to optimize to handle different payment periods
double n = years * 12;
double rPower = pow(1+r,n);
double paymentAmt = loanAmount * r * rPower / (rPower - 1);
double totalPaymentd = paymentAmt * n; 
double totalInterestd = totalPaymentd - loanAmount; 
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:2];
NSNumber *n1 = [NSNumber numberWithDouble:paymentAmt];
NSNumber *n2 = [NSNumber numberWithDouble:totalPaymentd];
NSNumber *n3 = [NSNumber numberWithDouble:totalInterestd];
NSString *paymentAmtString = [numberFormatter stringFromNumber:n1];
monthlyPayment.text = paymentAmtString;
NSString *totalInterestString =[numberFormatter stringFromNumber:n3];
totalInterest.text = totalInterestString;
NSString *totalPaymentString =[numberFormatter stringFromNumber:n2];
totalPayment.text = totalPaymentString;
}

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}


- (void)dealloc {
[tbxLoanAmount release];
[annualInterestRate release];
[noOfYears release];
[monthlyPayment release];
[totalInterest release];
[totalPayment release];
    [super dealloc];
}

@end


Explanation






#import "EasyLoanCalculatorViewController.h"

Import the header file which we have just coded.

@implementation EasyLoanCalculatorViewController

@synthesize tbxLoanAmount;
@synthesize annualInterestRate;
@synthesize noOfYears;
@synthesize monthlyPayment;
@synthesize totalInterest;
@synthesize totalPayment;

The synthesize keyword just means generating the getter and setter methods for each of the UIControls which we have declared in the .h file.

-(IBAction) bgTouched:(id) sender{
[tbxLoanAmount resignFirstResponder];
[annualInterestRate resignFirstResponder];
[noOfYears resignFirstResponder];
}

This is the first Action we have declared earlier in the .h file. Ignore this for now.

-(IBAction) btnCalculate:(id) sender{

Start to implement the btnCalculate Action. Its essentially a method. We name the method btnCalculate that takes an argument of id type and call it sender.
double loanAmount = [tbxLoanAmount.text doubleValue];
double intRate = [annualInterestRate.text doubleValue];
double years = [noOfYears.text doubleValue];

Declare some double variables, and assign the value of the text property of the Textbox. i.e. what the user typed in. Before assigning it, change it to a double type. [tbxLoanAmount.text doubleValue] is essentially tbxLoanAmount.text.ConvertToDouble(); 

To generalize, obj.method() in objective c is [obj method];
double r = intRate/1200; // to optimize to handle different payment periods
double n = years * 12;
double rPower = pow(1+r,n);
double paymentAmt = loanAmount * r * rPower / (rPower - 1);
double totalPaymentd = paymentAmt * n; 
double totalInterestd = totalPaymentd - loanAmount; 

Above should be reasonably understood unless you have never coded before. Perhaps what is more difficult to understand who be the formula itself. But you worry about it, you can change the formula to what you want, its just a financial formula which can be readily changed to anything formula you want.
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setMaximumFractionDigits:2];

NSNumber *n1 = [NSNumber numberWithDouble:paymentAmt];
NSNumber *n2 = [NSNumber numberWithDouble:totalPaymentd];
NSNumber *n3 = [NSNumber numberWithDouble:totalInterestd];

NSString *paymentAmtString = [numberFormatter stringFromNumber:n1];
monthlyPayment.text = paymentAmtString;
NSString *totalInterestString =[numberFormatter stringFromNumber:n3];
totalInterest.text = totalInterestString;
NSString *totalPaymentString =[numberFormatter stringFromNumber:n2];
totalPayment.text = totalPaymentString;
Will discuss the above in depth in a separate article. Essentially, its creating the Formatter object to format a double to 2 decimal places. And converting the double values into a string to assign them to the labels.text property. So, out the calculated results to the labels - monthly payment, total interest and total payment.

}

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}

Certain events that the program throws. But we do not have to handle them for the moment.


- (void)dealloc {
[tbxLoanAmount release];
[annualInterestRate release];
[noOfYears release];
[monthlyPayment release];
[totalInterest release];
[totalPayment release];
    [super dealloc];
}

Called when the program exits, release all my objects used for the UIControls.

@end

Await Part 3 where we will link the Outlets to the UIControls and buttons to the Actions.
And of course, build and run the app.