Archive for the ‘Dev Center’ category

Passing data between classes

May 2nd, 2009

If you are trying to create a big project, I recommend you to create many classes to handle every single bigger task. Why? If one class contains 400 lines of code it’s ok, but when it grows, scrolling and finding something between 2000 lines isn’t just nice and cause confusion. You may say that comments can help you. Well, not in that case. Comments help you to understand the code below them if you return to it after some time, but not to locate some minor features of project.

I advice you to create many classes – like UIViewController, and name them properly. I like to have the complete menu of the application in one single class operating on 10-20 views. I can create a single animation that after some assignments allows me to switch any two views with transition. But class responsible for entering high-scores, with all the data common only to this class, special set of animations and others just don’t suit to my menu class, and that’s why I decide to put it in the other source file.

Today, I’m going to show you how to create a project, where on the first view user has a login field (UITextField), and once he pressed a button (UIButton), the next class is allocated, and the login he has just entered  is displayed on it’s view.

This is called passing data between different classes. Today, I will describe you how to pass the NSString value, but using the same or similar steps you can pass anything else.

Xcode

Let’s start be creating the project and adding there two classes: login and account, both UIViewControllers and two views – again: login and account. In app delegate add the standard lines:

#import "login.h"
@class login;
	login *viewController = [[login alloc] initWithNibName:@"login" bundle:[NSBundle mainBundle]];
	[window addSubview:[viewController view]];

In login’s header add the UITextField visible for interface builder and the action (when user presses the button). Also add the protocol: UITextFieldDelegate. For example:

#import <UIKit/UIKit.h>
@interface login : UIViewController <UITextFieldDelegate> {
	IBOutlet UITextField *nickname;
}
-(IBAction)submit;
@end

Now, double click login.xib and design a view. Drop UIButton, UITextField, customize them in the way you want. Set login.xib class login, and assign connections: view => view, nickname => text field, submit action => button’s touch up inside. That’s almost all, but as we extend the UIViewController with protocol UITextFieldDelegate we would like him to give as a signal for some predefined actions called by UITextField (hiding the keyboard for example), that’s why, you need to click on UITextField, and in text field connections, connect delegate with File’s Owner.

You can close login.xib, this part is done, login.m will be implemented later, let’s now move to account.h. You need to create two instance object and one property:

@interface account : UIViewController {
	IBOutlet UILabel *loginLabel;
	NSString *nickname;
}
@property (nonatomic, retain) NSString *nickname;

The NSString nickname will be in near future loginLabel’s text. Setting the property allows me to access this object from outside. (nonatomic, retain) means, that it will be the same object, not the copy etc, (using different keywords here, you can set read only, copy and more, but on the beginning you will only use nonatomic, retain). Before the property will work, you need to synthesize this property in implementation.

#import "account.h"

@implementation account
@synthesize nickname;

And now design viewDidLoad method:

- (void)viewDidLoad {
     loginLabel.text = nickname;
     [super viewDidLoad];
}

Open account.xib with Interface Builder, set it’s class account, add a label and connect it with loginLabel and the view as usuall. Save and close Interface Builder.

Now let’s go back to login.m, import the account.h and implement the missing method submit.

#import "account.h"
@class account;
-(void)submit {
	account *Acc = [account alloc];
	Acc.nickname = nickname.text;
	[self.view addSubview:Acc.view];
}

First line is creating new (and only one) object of account class. 2nd line is setting the property using text from UITextField, and adds the account’s view as a subview to current view. When you run the project right now it will work but the keyboard cannot be hidden. Because you set the nickname (UITextField), as a delegate to this class (File’s Owner), you can implement this method to dismiss the keyboard after pressig Return Key:

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
	[theTextField resignFirstResponder];
	return YES;
}

Above method not only can hide the keyboard (resignFirstResponder and return YES), but as well call the submit method:

- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
	[theTextField resignFirstResponder];
	[self submit];
	return YES;
}

That’s all, you can complete dealloc methods on your own.

Please note:

Please note #1: you could set as property not only a nickname (NSString), but as well loginLabel (UITextField), but you can only modify UITextField once the view is loaded, because before the viewDidLoad method is called, it’s an empty – nil object. In future you may add account’s view and change it alpha to zero, so the view is loaded but is full transparent, but you have full access to any objects like UITextField. Later, simple change the alpha back to 1.

Please note #2: remember to synthesize all properties

Please note #3: you can pass this way almost everything, but the property can look a little bit different. Objects need a nonatomic and retain keyword (or other if needed), but passing int, float, double, boolean as long as they are not objects, they only need a nonatomic keyword:

@property (nonatomic) int magicNumber;

Please note #4: the definition of object should be exacly the same as definition of property, don’t forget IBOutlets, types, stars:

IBOutlet UILabel *myLabel;
UILabel *programmaticalLabel;
bool myLogicValue;

@property (nonatomic, retain) IBOutlet UILabel *myLabel;
@property (nonatomic, retain) UILabel *programmaticalLabel;
@property (nonatomic) bool myLogicValue;

That’s all. Sample project for you.

xcodeproj

Download the project

Logs

April 29th, 2009

logs

Logs give you a great opportunity to know the current progress of your application, track changes and find strange problems.

As you see on the screensht above, the Debugger Console window of project Logs is open. You will find it Xcode: Run => Console, or simply: Command+Shift+R.

Logs give you the many information, like when the program started and what cause the unexpected quit.

When I started programming I used a lot of UIAlertViews, to know the current state of my application, the knowledge what method has been just called. But alerts are not good for it. Each time the new alert is shown, the previous one is hidden, until you dismiss the one from top, and then you see them in backwards order – it’s very easy to get lost. That’s why it’s best to use NSLog.

To add your own log you have to use a single line of code:

NSLog(@"newLog");

And when you open the console you should see next row: with date, time, project’s name, memory address (don’t care about this now) and the log itself.

Of course you can save to logs not only defined text, but variable as well simply using NSString:

int someNumber = 5;
NSString *someText = @"asdfg";
NSLog([NSString stringWithFormat:"someNumber: %i ; text: %@",someNumber,someText]);

Isn’t it easy? Yes it is, maybe on the beginning, you don’t need them at all, but believe me, they will be helpful when your project grows.

Of course when your app is finished you should disable the logs for the performance improvements and not to prevent, anybody will read the log file with our logs content. I know a lot of people really like to add very sophisticated logs like:

NSLog(@"Oh yeah man, do it again, I like that");
NSLog(@"I will tell your mother");
NSLog(@"You messed sth up!!!!");
NSLog(@"Oh F***");

Believe me or not, but this kind of logs tell you more than NSLog(@”method doSomething called”);.

So, to disable them, you can either delete them all, or disable by using a comments // before each log:

// NSLog(@"log content");

Logs can be really helpful when you develop a game. In early development when you detect a collision, save such an info as a log instead of losing a life and restarting level. Using this way you will easier track and bugs, dead-zones and more.

An as usuall:

xcodeproj

Download the project

Memory Management

April 29th, 2009

iPhone SDK doesn’t use anything like Garbage Collection, you might now from the other programming languages. What does it mean? It means that whenever you create – alloc any new object, it’s “locked” in the memory until you release it. If you application terminates and you didn’t release it properly it will stay in the memory, so other application will crashed at any time when they need more memory than it available at that particular moment.

You shouldn’t think only about Memory Management, to be kind and to respect end-user and other developers work. If your application causes too many memory leaks, there is high likelihood that your application won’t pass Apple Revision. Using Memory Management properly you even help yourself. If your application generates a lot of object, but most of them are used only for a limited time, get rid of them as long as they are not necessary.

What is memory leak?

When you allocate the object or simply create a new object using any other method it’s unique name acts as a pointer to that class. I will give you an example. You have a method that displays an alert:

-(IBAction)showAlert {
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"message" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
	[alert show];
}

Whenever you call above method you generate a memory leak. You have allocated an object alert of type UIAlertView, but once this class is called, you don’t have any access to alert in any other method as it was allocated locally. Alert is displayed, pressing the Cancel button, hides it, but it stays in the memory, waiting for any other commands to execute. If you call this method again, although it allocs the next UIAlertView with the same name alert, it’s completely different object.

If you test this application with Instruments: Object Allocations/Memory Leaks, the number of UIAlertViews allocations will only grow. You can also use a NSTimer (in viewDidLoad method) and call this method frequently to understand the gravity of situation:

[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(counter) userInfo:nil repeats:YES];

How to fix it? Add: [alert release];, after [alert show];. What does release acctualy do? It frees the memory, forgets about the pointer alert, so you can no longer use it, but the part of memory where the alert took, can be used again. Once you call release, it doesn’t mean that the object disappears from the user interface, but you have no longer access to its properties.

Let’s give another example, this time with UILabel. As you know, UILabel can be used to show single line text. Of course you can change it’s background color, text, shadows colors etc. But sometimes label can be more, sometimes less important. You can use the UILabel to show the current status of your application, some values, – so in this case UILabel is frequenlty changed (at least it text property). But you can also create the UILabel only to display some kind of header, static description, copyrights on the bottom, – and once you allocated it, you never change it again:

UILabel *copyrights = [[UILabel alloc] initWithFrame:CGRectMake(0,390,320,30)];
copyrights.text = @"(c) www.chris-software.com";
copyrights.backgroundColor = [UIColor clearColor];
[self.view addSubview:copyrights];
[copyrights release];

As you see, in above example I created UILabel, customized it a little bit, added it to the view and throwed it away from the memory. If I used the command [copyright release]; for example above [self.view addSubview:copyrights];, my app would unexpectly quited because of the error – when app wanted to add a subview it wouldn’t know what copyrights is.

And what if I frequently change the UILabel’s properties? I should define it in header file of current class (.h) and since then you have the access to this variable in any methods. You can alloc it in viewDidLoadloadView, any other method, or even in Interface Builder. Than release it once it’s not needed any more. When you are not sure if you need this label or not, don’t worry, you can release it in:

-(void)dealloc

dealloc method is one of the methods that are automatically called. For example in UIViewController, loadView method is called once you alloc the viewController (only if you implement this method), viewDidLoad is called when the view is added as a subview of something else for the first time. The same is with dealloc, but this method is called when the user quits the application. Inside this method in most cases you should release any object you mentioned in header file which was allocated either programmaticaly or in Interface Builder – you connected an object with an outlet.

Common mistakes

  1. You have in header file four menu buttons: IBOutlet UIButton *button1, *button2, *button3, *button4;, and the one another button UIButton *animateButton;. Only button1-4 were allocated somewhere. As I name the button animateButton, for sure I’m going to perform some constant animations on it. There is a magic trick, that allows you, using animateButton animate any of buttons button1-4. When in code, I type animateButton = button1, it doesn’t mean that animateButton is a copy of button1. It’s just a pointer, so from now, both animateButton and button1 refers to the same object. Later when I type animateButton = button2animateButton is pointing only to #2. So when it’s time to release buttons from the memory, I have to release only button1, button2, button3, button4, why not animateButton as well? Because I never allocated it, it was only the pointer to one of the buttons. And from the other way. If I type animateButton = button4, I can release animateButton, and now I don’t have to (I shouldn’t) release button4 and vice verse.
  2. You don’t have to release everything what has a “star”: * before the name. One of the examples I presented above. Just remember the number of alloc words should be equal to release. Although some objects can be allocated without alloc method. You can create an button using [UIButton buttonWithType:UIButtonTypeRoundedRect], but it doesn’t mean you don’t have to release it.
  3. NSTimer… Once you invalidated a timer, don’t release it. [myTimer invalidate] is enough.
  4. What about int, float, double, bool…? Forget about them.

Hope this article helped. I discussed with you everything using examples with alerts and labels. Here your leaks won’t be greater than few kilobytes each, what in sum can give you preattay big amount in megabytes later. Please don’t ignore it. Have you ever though what would happen with stability and performance of the device when you forget to release a 100MB movie? The more leaks generated the more often end-user has to reboot his iPhone / iPod Touch. Also, when possible use the lowest needed resolution images. Don’t add big images only to scale them down, and avoid compression like JPEG.

I can’t include any sample project here :-) . I don’t won’t to distribute projects with memory leaks signed with my name…

Loading images

April 29th, 2009

uiimagepickerThe Photos on every single iPhone / iPod touch can be shared with others apps – even your own. Using UIImagePickerController, you are allowed to access any photo from the device or even take a new one with the camera.

You might have never noticed it, but the same method I’m going to present you, is used in the official Apple built-in applications like Contacts, when you assign a photo to any contact, and Settings while choosing the wallpaper.

This method is not only useful in creating next Photo manager apps  or simple editors.

Before you start you need to add two protocols to your class (header .h) which will handle UIImagePickerController. These two protocols  are: UIImagePickerControllerDelegate and UINavigationControllerDelegate. Your interface code should look like this:

@interface MyView : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate> {

Once you’ve done that it’s time to implement a method that will show the UIImagePickerController. I use:

 

-(IBAction)openAlbums {
	if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
		UIImagePickerController *UIPicker = [[UIImagePickerController alloc] init];
		UIPicker.allowsImageEditing = NO;
		UIPicker.delegate = self;
		UIPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
		[self presentModalViewController:UIPicker animated:YES];
	}
	else {
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Error" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
		[alert show];
		[alert release];
	}
}

openAlbums method as it’s an IBAction will be called by pressing a button in my case. In bold I highlighted the most important parts. The if statement, checks if asked source type is available (for example, camera is not available on the iPod Touch). If yes, I’m allocating the UIImagePickerController setting delegate, source type, and disable edition, otherwise the alert-error is displayed.

Please note #1: always set to the same property for sourceType and isSourceTypeAvailable. Otherwise, checking if source type is available is pointless.

Please note #2: if you set YES to the property allowsImageEditing, you have the same options of “edition” like in setting the wallpaper, that is resizing and moving.

UIImagePickerControllerSourceTypePhotoLibrary shows you the list of all your albums, which you can browse to choose a photo. There are 2 others source types.

  • UIImagePickerControllerSourceTypeSavedPhotosAlbum
    strictly Camera Roll, where your photos from camera, screenshots, and photos saved by applications are.
  • UIImagePickerControllerSourceTypeCamera
    uses the camera, to take new picture
    Please note: the iPhone simulator can display the camera controller but it won’t use neither iSight nor any other device as a preview. When you take the picture you get the permanent animating activity indicator and you can’t go back, only restart your app.
    simulatorcamera simulatorcameratook

Before you go to the next stage, you should create an UIImageView (IBOutlet UIImageView *imageView;) and place it somewhere on your view, where image you picked, will be displayed. I recommend you to set imageView’s mode property to Aspect Fit to prevent resizing, when the picked image is bigger than imageView’s frame.

Now, you have to implement two more UIImagePickerController methods that will be called when you’ve picked an image or cancel picking.

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
	imageView.image = image;
	[[picker parentViewController] dismissModalViewControllerAnimated:YES];
	[picker release];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
	[[picker parentViewController] dismissModalViewControllerAnimated:YES];
	[picker release];
}

The first method is called once you picked a photo using any source type, the second one is called when you cancel picking. Both methods look almost the same – both of them remove the UIImagePickerController by dismissModalViewControllerAnimated:YES and frees the memory. didFinishPickingImage method has one more line of code: imageView.image = image;. It changes the image property of imageView, so from now imageView displays picked image.

Very annoying problem:

pickerproblem

As you see on the example above, status bar is above UIImagePickerController and it doesn’t look good, does it? There are two ways of solving this problem.

  1. Hide the status bar in either the whole your application in the AppDelegate, or if you need it, hide the status bar when you call UIImagePickerController, and show it again in in both two methods: didFinishPickingImage and imagePickerControllerDidCancel.
  2. If you don’t want to use any magic tricks showing and hiding the status bar, in other words you want the status bar to be permanently visible, you are making one mistake since a longer time that has never caused any problems. Your views are of size 320×480px when you only need 320×460px. Go to your view’s size and set the height (H:) to 360. Now in App Delegate where you are adding the view as a window’s subview change the view’s center:
	MyView *viewController = [[MyView alloc] initWithNibName:@"MyView" bundle:[NSBundle mainBundle]];
	[window addSubview:[viewController view]];
	viewController.view.center = CGPointMake(160,250);

Please note: on iPhone Simulator the UIImagePickerController shows immiedietly. On real device it takes few seconds (depending on the size of your photo library) before UIImagePickerController will be shown for the first time.

Here is my project:

xcodeproj

Download the project

Creating a view programmatically

April 29th, 2009

Now it’ time for something more advanced. In Interface Builder how-to I told you, that I.B. is great for designing interfaces, but there are cases this knowledge – creating everything programmatically will be necessary and helpful, like:

  • there is an unknown number of object which will be added
  • the number of object is static but enormous, and they are almost the same with tiny differences
  • you want to be better than others and you like hard not-needed extra work…

Let’s start. So far you created everything in Interface Builder, you were editing NIB (.xib) files, but in fact Interface Builder created the whole code for you in the background.

As I mention in article about I.B. I told you, that you can create the Interface only in I.B., partialy in I.B. and Xcode or only in Xcode.

I personally advice you to use Interface Builder wherever possible using Xcode when necessary, if some properties cannot be set in I.B.. In this article I will show you how to create everything using only Xcode. Let’s start.

Whenever you created any object to be visible in Interface Builder you used the keyword IBOutlet for example: IBOutlet UILabel *myLabel;. If you customize in this case myLabel in Xcode only, you can skip this keyword, so: UILabel *myLabel;. The same with any methods / actions, you were using IBAction what in fact is an equivalent to void (no value returned), but IBAction gives you one advantage – that it’s visible in I.B.. So if are impementing a method that will be called by objects created only in Xcode you can use: -(void)myAction; instead of -(IBAction)myAction; and of course if you need to know what object called the method: -(void)myAction:(id)sender instead of -(IBAction)myAction:(id)sender.

Creating a view programmaticaly

Let’s start by creating programmaticaly a view. Let’s add a UIViewController class, name it MyView.m (and MyView.h). In you AppDelegate’s header add standard lines:

#import "MyView.h"
@class MyView;

and in AppDelegate’s implementation:

MyView *viewController = [MyView alloc];
[window addSubview:viewController.view];

Now go to MyView.m, and find somewhere the commented loadView method, it should look like:

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

Deleate /* and */ to activate this method. During allocating of this class (or any UIViewController) the loadView will be automatically called to load the view (and BTW, once view is loaded viewDidLoad is called). Extend loadView class by these two lines:

	self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
	self.view.backgroundColor = [UIColor yellowColor];

If you Build and Go you will get the empty yellowyellowview screen (with status bar of course).

Why?

It’s simple. first line is creating a new view [UIView alloc]. Because MyView class is UIViewController it already expects a view. So far, you created a view in Interface Builder connecting view outlet to view’s preview, if I can call it like this, this time you created it programmatically. The second part is creating the view’s frame, you are setting the coordinates and size of view. Quick info about CGRectMakes’s arguments:

CGRectMakes(xTopLeftCorner,yTopLeftCorner,width,height)

The 2nd line is quite obvious, just changing the background color. Hmm, but where did you put anything to make this view visible? Answer: in AppDelegate implementation file. So, to be more specific, visit your …AppDelegate.m file:

  • MyView *viewController = [MyView alloc] is creating new object of class MyView and automatically calls loadView method, so you don’t have to
  • [window addSubview:viewController.view] is adding the view created by loadView to the application window

Hope it’s clear now.

Adding a label programmatically

Add this block of code to loadView or viewDidLoad method:

	UILabel *myLabel2 = [[UILabel alloc] initWithFrame:CGRectMake(50, 200, 200, 80)];
	myLabel2.text = @"only Xcode";
	myLabel2.textAlignment = UITextAlignmentCenter;
	myLabel2.textColor = [UIColor yellowColor];
	myLabel2.shadowColor = [UIColor whiteColor];
	myLabel2.shadowOffset = CGSizeMake(1,1);
	myLabel2.font = [UIFont fontWithName:@"Zapfino" size:20];
	myLabel2.backgroundColor = [UIColor greenColor];
	[self.view addSubview:myLabel2];
	[myLabel2 release];

Code is similar to that one, where you created the view. Differences? [UILabel alloc], not [UIView alloc] and another frame which suits me. Next 7 lines is a customization of label – changing label’s text, text alignment, text color, shadow, font, also background color. To show label on view you use [self.view addSubview:myLabel2];. I’ve already told you once, but I will repeat, almost everything visible on iPhone / iPod touch is some kind of view. UILabel is also UIView’s subclass.

The last line contains: [myLabel2 release]; it frees our memory, but use it wisely. This time I didn’t put it into dealloc method that is called when application terminates. Hmmm… no…, read the article about Memory management and you will see the point.

Now your app should look like this:

yellowviewlabel

You can easily add next label, remember to give it an unique name:

	UILabel *myLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 200, 80)];
	myLabel.text = @"Isn't it amazing?";
	myLabel.textAlignment = UITextAlignmentCenter;
	myLabel.backgroundColor = [UIColor colorWithRed:0.2 green:0.9 blue:0.5 alpha:0.3];
	[self.view addSubview:myLabel]; 

Creating a button programmaticaly

Let’s start with the code:

	myButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] initWithFrame:CGRectMake(50, 300, 200, 80) ];
	[myButton setTitle:@"And a button" forState:UIControlStateNormal];
	[myButton setTitle:@"Alert :D " forState:UIControlEventTouchDown];
	[myButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
	myButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
	myButton.backgroundColor = [UIColor clearColor];
	[myButton addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
	[self.view addSubview:myButton]; 

As you see above, this time I didn’t use something like [UIButton alloc], but [UIButton buttonWithType:...]. Why? Because I had to, if the button was simply an image I would use alloc, but as long as I want to use the predefined type I had to create it using above command.

Now you might ask a question why I set some properties using [myObject something:], and others using myObject.something=. Answer: some properties can be set using both of these two ways, some only using one. For example  in UILabel:

myLabel.text = @"asdfg";
[myLabel setText:@"asdfg"];

are the equivalents. So comming back to my button, I set two different titles, one is displayed during normal state of button, and the other while it’s being pressed, next color, alignment, backgroundColor. Later I connected an action to the button – in bold is a name of method called when user will TouchUpInside – press the button. All you need to do is to implement the buttonAction method:

-(void)buttonAction {
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hmmm" message:@"It really works :) " delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil];
	[alert show];
	[alert release];
}

If you would like to have info about what object called the method [(id)sender], add a colon on the end of class name in adding a selector to the button:

	[myButton addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];

And of course:

-(void)buttonAction:(id)sender {
	//...
}

One thing you have to know

When you set a frame using CGRectMakes(TopLeftX,TopLeftY,width,height), or the center using CGPointMake(CenterX,CenterY), you need to know something more. These two x, y coordinates of top left corner or center point, are set according to the view (or it subclass) that our object is subview of . So let’s say you have a view 320×480px, but it is not placed in the center of the screen (window), it’s a little bit to the left. If you add a UILabel as the view’s subview and set the center property of that label equal CGPointMake(160,240), it will be in the exact center of the view, but together with the view moved a little bit to the left.

Conclusion

As you see, designing an interface strictly in Xcode is a little bit tiring, but there will be cases you will have to use it in practise. The difficult maybe the lack of knowledge what property customize some key and less importan parts of given object. Everything can be find in documentation. You can also get a list of all available properties pressing Esc-key after “myObject.” or “[myObject “.

As usuall I prepared a project for you, so if something doesn’t work for you, compare it with mine.

noibend

xcodeproj

Download the project

View transitions

April 28th, 2009

Using view transitions will give a lot of beauty to your entire application. So far there are implemented 4 transitions:

  • Curl Up (UIViewAnimationTransitionCurlUp) – check Maps application on iPhone, but it’s not best example. Simply: page flip; curls a view up from the bottom
  • Curl Down (UIViewAnimationTransitionCurlDown)
  • Flip from right (UIViewAnimationTransitionFlipFromRight) - execly the same like in Weather app when you press info button; flips a view around a vertical axis
  • Flip from left (UIViewAnimationTransitionFlipFromLeft)

The code for setting a view transition is almost the same like for any other animation, here is the example:

	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:1.5];
	[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:placeholder cache:YES];
	[view1 removeFromSuperview];
	[placeholder addSubview:view2];
	[view2 removeFromSuperview];
	[placeholder addSubview:view1];
	[UIView commitAnimations];

I have a view called placeholder and it’s added as a part of self.view of the view controller. view1 and view2 are two different views I want to transit go from view1 to view2 and vice verse. placeholder is of the same size as both view1 and view2. During this animation / transition placeholder flips around hiding view1 and revealing view2. During the transition, everything what is below placeholder is partialy visible. The animation takes 1.5 seconds as u set in setAnimationDuration.

Please note #1:
It’s only an animation, not real rotation / flip of placeholder let’s say it an optical illusion. UIView (what placeholder is) doesn’t have something like back and front side. view1 after transition is not hidden behind the placeholder, it has been removed, and you still see the front side of placeholder although it’s covered by view2, which is a placeholder’s subview.

Please note #2:
Unfortunately you can’t see the curl up / down transition on iPhone Simulator, it looks like fade, but it really works on real device.

Please note #3:
If view that animate’s in my case placeholder (yes placeholder animates, view1/view2 are only added/removed) is bigger than view1/view2 you will always see front site of that part although it will animate too.

Please note #4:
If you see annoying white part during animation, simply add something black below the placeholder – another view or image for example.

Fade transition

As I told you there are only 4 transitions, but many are curious how to make the fade transition. It’s very easy, simply create a normal animation which will change the alpha property for both views:

[placeholder addSubview:view2];
[placeholder addSubview:view1];
	view2.alpha = 0;
	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:1.5];
	view1.alpha = 0;
	view2.alpha = 1;
	[UIView commitAnimations];

I prepared for you a project you can download and test Curl Up, Curl Down, Flip From Right, Flip From Left, Fade and also Flip From Left again but along the self.view, not placeholder.

flip1flip3flip2

xcodeproj

Download the project

Status bar

April 28th, 2009

Status bar is a tiny rectangle ( 320 x 20 px) on top of your screen, showing you you carrier’s name, range, time and battery status.

statusbar

This part is very useful while developing applications – utilities, but as far as I remember, when I started programming I was really confused how to hide it.

While designing the view in Interface Builder in view’s attributes tab you can set Status Bar = None, but it’s still there. Nothing will happen if you set Status Bar property for MainWindow.xib.

If you would like to get rid of status bar you must do it in Xcode. It’s just a single line of code:

	[[UIApplication sharedApplication] setStatusBarHidden:YES animated:NO];
It will make the status bar vanish. If you want to remove it via alpha transition set animated:YES. If you don’t want to have status bar anywhere in whole your application, you should do it in implementation of AppDelegate file ([project_name]AppDelegate.m) before you will add any subviews to the window, for example:
- (void)applicationDidFinishLaunching:(UIApplication *)application {    
	MyView *viewController = [[MyView alloc] initWithNibName:@"MyView" bundle:[NSBundle mainBundle]];
	[window addSubview:[viewController view]];
	// Override point for customization after application launch
	[window makeKeyAndVisible];
}

Status bar’s styles

By default status bar is gray – shown as an image example above. You can quickly change it, so it will be like in Springboard (black) or during YouTube video playback (black translucent – showing what’s behind him).

barblack

bartranslucent

Code:

	[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];
	[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:YES];
	[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault animated:YES];

As before using animated boolean property you can change the status bar with transition or without.

Orientation

There is another article about handling interface autorotation, but changing the status bar orientation is easy.

	[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:YES];
	[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
 	[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
	[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortraitUpsideDown animated:YES];

Please note: Using iPhone Simulator changing the orientation of status bar, automatically turn the defice to landscape / portrait mode, without changing the interface orientation (how to handle this, I will present in another tutorial).

That’s it. Sample project for you.

statusbarsimulator

xcodeproj

Download the project

Making screenshots

April 28th, 2009

iPhone / iPod touch allows you to make screenshots (saves the contents as an image) by pressing both home and power button, although many users don’t know this functionality. If you go to your camera roll or sync photos with your computer, every screenshot you make is an image 320 x 480 px.

Today I will show you how to make a screenshot of arbitrary size using Quartz. What does arbitrary size mean? Well you can not only save the smaller part of your screen, but, if you for example have bigger view than 320×480 px you can save it all, not only the visible part.

Before you start, you have to add the QuartzCore framework to the project. All frameworks can be find here:

/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/ iPhoneOSxxx.sdk/System/Library/Frameworks

The part in bold can be different for each of you, in my case it’s iPhoneOS2.2.sdk. But there is much easier way to get to the Frameworks folder.

revealframeworkfinder

As you see above in Xcode, ctrl-press (or using your right mouse button) any of existing frameworks and choose Reveal in Finder.

finderframeworks

Now in Finder drag QuartzCore.framework to the Frameworks group into your project. It’s up to you if you decide to copy the item or simply link it. The framework has been added, now in the class which fill be making screenshots, you need to add a line to import the part of that framework:

#import <QuartzCore/QuartzCore.h>

You can add this line in either header (.h) or implementation file (.m).

Now it’s time to add the method which will make a screenshot and explain how it works:

-(void)saveToCameraRoll {
	UIGraphicsBeginImageContext(self.view.bounds.size);
	[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
	UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();
	UIImageWriteToSavedPhotosAlbum(viewImage, self, nil, nil); 

	/* 
	flashView.alpha = 1;
	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:0.5];
	flashView.alpha = 0;
	[UIView commitAnimations];
	UIAlertView *alert= [[UIAlertView alloc] initWithTitle:nil message:@"Photo saved to your camera roll" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
	[alert show];
	[alert release];
	*/
}

I’ve implemented the saveToCameraRoll method were first five lines do everything you need. It’s quite difficult to discuss it, as long as I never mentioned about Quartz drawing, contexts, layers… But, first line creates the context of our view (UIViewController’s self.view) size. Using that context’s frame (it’s not frame properly speaking) it contents is rendered (2nd line) and saved to an viewImage. 4th line is closing the context as we do not need it anymore, and the 5th line puts viewImage to the Camera Roll.

How about the part in the comment ( /* and */ )? Well it’s my idea how to copy the animation iPhone uses while making the screenshot using home and power buttons. I created the flashView - simple white view of the same size of my self.view most time 100% transparent. When the user decides to create a screenshot using a button I provided in the application, flashView become visible and during half a second it’s transparent again. And the alert to inform what has just happen.

Please remember that above method saves the whole self.view and all it’s subviews. So whatever is a subview of self.view will be saved as well. You can change the alpha property of anything you don’t want to save and reveal what’s behind it, and after screenshot was made bring alpha to normal. While making a screenshot as long as it will be one procedure – one task user won’t see any changes in interface. Example:

-(void)saveToCameraRoll {	topView.alpha = 0;

	UIGraphicsBeginImageContext(self.view.bounds.size);
	[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
	UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();
	UIImageWriteToSavedPhotosAlbum(viewImage, self, nil, nil); 

	topView.alpha = 1;

}

As always (don’t thank me) I provided an sample project. It alows you to make screenshot of whole iPhone screen (320 x 480 px), only central part (320 x 240 px) and again the whole iPhone screen without button on the bottom.

screenshotssimulator

xcodeproj

Download the project

Ohh, I would forget. One thing more. Making screenshots on simulator is very quick, unfortunately, it takes few more seconds to render everything on real device.

Colors

April 27th, 2009

Most colors you will set in Interface Builder rather than in Xcode on the beginning, but if you need to change it dynamically, I’m sorry you need to know it.

I will present you the way how to change the background color of UIImageView – in other words image, using UIColor. By image I mean simply placeholder for image, because UIImageView can be just a colored rectangle without any PNG/JPG at all. But UIColor is very flexible, using the same code, you can change not only background colors, but shadow shadowColor (for UILabel), textColor (also UILabel) and I’m sure there is even more properties I can’t remember in this particular moment.

The code is very simple (as usuall):

myImage.backgroundColor = [UIColor blueColor];

Above code will cause, that myImage’s frame will be blue.

You can experiment with a lot of colors like:

  • blackColor
  • brownColor
  • cyanColor
  • grayColor
  • greenColor

While in Xcode write “[UIColor " and press escape to a list of all possible ending and you will get a lot of standard colors you can use.

If you would like to make your image (or anything else) transparent in some percent you can use alpha property:

myImage.alpha = 0.5;

This will make your image half transparent.

RGB

Of course it's not all. iPhone / iPod touch are devices able to display millions of colors (so they said). I have never counted them but it's very easy to display any color giving the amount of red, green and blue... and alpha at once.

The code is also a single line:

	image.backgroundColor = [UIColor colorWithRed:121/255 green:42/255 blue:120/255 alpha:0.9];
Above sets the image's frame color RGB(121,42,120) which opacity is 90%. You need to know one thing about above structure especially the alpha part. If you set this color as a backgroundColor for UILabel, only the background will be transparent in 10%, the text will be visible in 100%.

Predefined textures

There are already to predefined textures you can use as a color. They are:
viewFlipsideBackgroundColor
flipsidetexture
groupTableViewBackgroundColor
groupedtexture

Depending of brightness of your screen viewFlipsideBackgroundColor looks like some kind of black material. I guess every iPhone user is familiar with the second one, it's the same background as grouped UITableView uses (see Settings application). You can use them like they were a normal color.

myImage.backgroundColor = [UIColor viewFlipsideBackgroundColor];
myImage.backgroundColor = [UIColor groupTableViewBackgroundColor];

One more thing

There is an interesting color clearColor. What does it to? Well maybe it wan't be important right now, as long as you can change any object's property alpha to zero. But clearColor will simply erase any color, very helpful in 2D graphics (Quartz).

Another one more thing

As usuall I prepared for you a project. An application where you can test any color you need changing the RGB and alpha using sliders and the preview of viewFlipsideBackgroundColor and groupTableViewBackgroundColor.

xcodeproj

Download the project

colorssimulator

Random numbers

April 27th, 2009

If you are creating an app with dynamical content, plot, random number is something definitely you need to know. Random number of enemies, random score for each smaller achievement, random number… forget about the reasons you need to know it!

There are few functions in iPhone SDK that gives you random number. The best is arc4random(). Why best? Because, each time you call this function you get the random number, without performing any other randomize procedures.

int myRandomNumber;
myRandomNumber = arc4random();
int myRandomNumber2;
myRandomNumber2 = arc4random();

In above example myRandomNumber and myRandomNumber2 are two different integers, it will be amazing coincident if they are the same.

There is one thing you need to know about it. arc4random() doesn’t ask you about the range of given number, in fact in most cases it returns you the random 8-9 digits numbers (positive or negative). But, using (un)known modulo operation (returns the remainder of division) you can get:

  • arc4random() % 10 : random number from range <0, 9>
  • arc4random() % 11 : random number from range <0, 10>
  • arc4random() % 2 : random number from range <0, 1>
  • arc4random() % 1000 : random number from range <0, 999>
  • arc4random() % 1001 : random number from range <0, 1000>

Now, using the know addition you can generate any range you wish:

  • 5 + arc4random() % 10 : <5,14>
  • 100 + arc4random() % 15 : <100,114>

I hope I won’t dissapoint You if I don’t include any sample project this time. For one simple function returning an integer 7 examples should be enough.