Archive for the ‘Obj-C Tutorials’ category

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.

Timers

April 27th, 2009

Timers – believe me or not, but they are useful not only in programming stopwatches.

Let’s give some examples.

  • To show a welcome screen and to close it after several seconds
  • You are making a game and you would like to display an info how long user is playing current stage, without comparing NSDate (start and current).
  • To create an animation without fade in / fade out effect.

Using timer (NSTimer) you are able to launch any task after given time or repeat it periodically.

I will give you an description with code for each of above examples.

Welcome screen

Welcome screen is shown only once during launch so there is no need to create any information in header file of your class about NSTimer. All you need to do is to add this line to your viewDidLoad method:

	[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(closeWelcomeScreen) userInfo:nil repeats:NO];
And to develop a closeWelcomeScreen method:
-(void)closeWelcomeScreen {
	[welcomeScreen removeFromSuperview];
}
closeWelcomeScreen will be called in 1.5 seconds after view was loaded. Remember to set the repeats property to NO this time. If you set YES, the method closeWelcomeScreen would be called every 1.5 seconds.
Right now we are simply removing the welcomeScreen, of course it’s up to you if you decide to perform an animation to change it’s alpha property it or to add something on top of welcomeScreen.

How long?

Now we will create a timer that will call the method every 0.01 second. In header file we need to add a float variable (float time;) and it’s also a label to show somewhere the value of this variable:

@interface MyView : UIViewController {
	IBOutlet UILabel *myLabel;
	float time;
}

Now in viewDidLoad or any other method you will call by yourself, add:

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

And you need to implement countTime method:

-(void)countTime {
	time += 0.01;
	myLabel.text = [NSString stringWithFormat:@"%.2f",time];
}

As you see, this time NSTimer’s repeats property is set to YES, and that’s why it will call countTime method every 0.01 second.

Animations using NSTimer

As I told you before using typical animations (and transformations) ([UIView beginAnimations:nil context:NULL] and [UIView commitAnimations]) you get the nice fade in and out effect. To perform a rotation for example you have to create a similar timer like in code above, with tiny difference. It won’t be changing label’s text but transforming it using each time bigger angle.

	[NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(countTime) userInfo:nil repeats:YES];
-(void)countTime {
	rotation += 0.001;
	myLabel.transform = CGAffineTransformMakeRotation(M_PI*rotation);
} 

Remember to add in your header file rotation variable: float rotation;

Stoping NSTimer

In each of above examples when NSTimer repeats itself you can’t stop it – the time will grow and/or your object will be rotated. To obtain it you have to add the NSTimer object to the header and later in implementation to use it’s invalidate method whenever/wherever you want to stop it. Below I show you an example of the timer that will make a full rotation of myLabel and invaliate itself.

Header:

@interface MyView : UIViewController {
	IBOutlet UILabel *myLabel;
	float rotation;
	NSTimer *rotationTimer;
}

Starting the timer:

	rotationTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(rotate) userInfo:nil repeats:YES];
And the rotate method:
-(void)rotate {
	if (rotation >= 2.0) {
		[rotationTimer invalidate];
		return;
	}
	rotation += 0.001;
	myLabel.transform = CGAffineTransformMakeRotation(M_PI*rotation);
}
You can call invalidate method anywhere in your project. A button can invalidate your timer or the timer itself as shown above.

Personal experience

Timers can be more complex than just counting a time or perform a simple task. If you use timer as a run loop of your game for example, be careful. If many methods can invalidate the timer you should check if it cannot be invalidated twice sometimes. It will crash your application. Although NSTimer has the boolean method isValid, once NSTimer is invalidated you can’t use this property. Declaring any NSTimer I also add the boolean variable with similar name:

NSTimer *myTimer;
bool myTimerInvalidated;

Each time I start the timer I set the boolean equals NO, each time I want to invalidate the timer I use:

if (!myTimerInvalidated) {
	myTimerInvalidated = YES;
	[myTimer invalidate];
}

Download the sample project to see live example of NSTimers.

xcodeproj

Download the project

Animations and transformations

April 26th, 2009

Using right animation / transformation can improve quality of your application. There are most important during game development.

You can use 3 basic transformations – you can marge them or invent your own. These 3 animations are:

  • rotation
  • scale
  • translation

animationsimulator

You can apply animation to almost everything – images (UIImageView), buttons (UIButton), toolbars, label, views…

Rotation:

Let’s say you have an image (UIImageView *myImage) and you would like to do something with it. To rotate it:

myImage.transform = CGAffineTransformMakeRotation(M_PI*0.25);

This will rotate image by 45 degrees right. Here are the typical values and their degree equivalents:

  • M_PI * 0.00 = 0° (original condition)
  • M_PI * 0.25 = 45°
  • M_PI * 0.50 = 90°
  • M_PI * 0.75 = 135°
  • M_PI * 1.00 = 180°
  • M_PI * -0.75 = 225°
  • M_PI * -0.50 = 270°
  • M_PI * -0.25 = 315°

If you would like to use degrees not the range <-1 ; 1> multiplied by M_PI you can define the constant value in header of your class: #define radianConst M_PI/180.0 (right under the #import lines). Now if you want to turn your image by 63 degrees use this:

myImage.transform = CGAffineTransformMakeRotation(63.0*radianConst);

Scale

Scale allows you to zoom in / zoom out your image. It’s more than simple scale, you can set the scale parameter different for image’s width and height. If you would like to have the image 2 times wider and 1.5 times higher try this:

myImage.transform = CGAffineTransformMakeScale(2.0,1.5);

Don’t be surprised that after this operation your image will be pixeled, that’s why in future you should provide images in higher resolution make them smaller on load (for example CGAffineTransformMakeScale(0.5,0.5)) and later when needed show them in original dimensions using CGAffineTransformMakeScale(1.0,1.0).

Scale gives you one more cool effect. If you set scale parameter as a negative value your image will be scaled and flipped horizontally or vertically. Examples:

  • CGAffineTransformMakeScale(-1.0,2.0)image flipped horizontally and twice higher
  • CGAffineTransformMakeScale(1.5,-3.0) – image 1.5 times wider, 3 times higher and flipped vertically
  • CGAffineTransformMakeScale(-2.0,-2.0)image 2 times bigger and flipped both horizontally and vertically

Translation

Translation is doing almost the same thing as changing the center value of any object. It moves image along X and Y axises. It’s the poorest so I will give you only 1 example and won’t talk about this any more.

  • CGAffineTransformMakeTranslation(50.0,20.0)image moved 50 pixels to the right and 20 to the botton

Similar effect you will get using center as I mentioned before: myImage.center = CGPointMake(140.0,90.0). Both of them has their own advantages and disadvantages, but let’s now move to something more interesting.

Animations

You know how to rotate an image (or anything else) by given degree, scale, flip, or move. How about creating a smooth animation? Well it’s very simple:

	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:1.5];
	// other animations goes here
	myImage.transform = CGAffineTransformMakeRotation(M_PI*0.5);
	// other animations goes here
	[UIView commitAnimations];

This code will smoothly rotate your object by 45 degress during 1.5 seconds. Please note, that while performing any animation the application continue to run next tasks – doesn’t hold for a given amount of seconds. If you would like your app to do an action when the animation is finished you can use either the NSTimer:

[NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(nextMethodName) userInfo:nil repeats:NO];

or extend your animation code by it’s delegate and selector:

	[UIView beginAnimations:nil context:NULL];
	[UIView setAnimationDuration:1.5];
	[UIView setAnimationDelegate:self];
	[UIView setAnimationDidStopSelector:@selector(nextMethodName)];
	myImage.transform = CGAffineTransformMakeRotation(M_PI*0.5);
	// other animations goes here
	[UIView commitAnimations];

Remember that second example is much more efficient, but in that case, nextMethodName (whatever you name it) must return a boolean YES – not void which doesn’t return any value at all. Example:

-(BOOL)nextMethodName {
 	// some tasks
	return YES;
}

Animations can be great to have transitions between two views but I will talk about them in other article.

Two transformations at once

Using any of above transformations you are modyfing only one property – transform of a given object. For example the code:

myImage.transform = CGAffineTransformMakeScale(2.0,1.5);
myImage.transform = CGAffineTransformMakeRotation(M_PI*1.0);

will give you the image rotated by 180 degrees, but won’t be scaled – scale was canceled after making rotation.

If you would like to merge two transform use the following code:

animateLabel.transform = CGAffineTransformConcat(CGAffineTransformMakeScale(2.0, 1.5), CGAffineTransformMakeRotation(M_PI*1.0));

I personally really don’t like this. I didn’t enjoy matrices during Mathematics in school. Any transform creates the matrix and CGAffineTransformConcat is multiplying two matrices – the order is necessary. If you wanted to merge three transforms you would have to use CGAffineTransformConcat merging two transforms as an argument of another CGAffineTransformConcat mergin previous merge with next transform. Sound difficult? Yes, for me two.

Original shape

To conclude, if you would like to quickly cancel any transforms use CGAffineTransformIdentity as a transform property of any object.

myImage.transform = CGAffineTransformIdentity;

I guess it’s all you need to know about transforms and animations right now. Below you can download my project where you can rotate, scale, translate any object using sliders and watch the smooth scale animation.

xcodeproj

Download the project