Fun with Django ManyToMany Fields

This is just another reason I find Django so easy.

For example.. Say you are making a monitoring application. Now you have a bunch of servers and you have certain groups of servers. A server can belong in more then one group also. So that is pretty easy and all with Django.

Now in your template you have a few pages. One page that displays the group information like all the servers in the group and another that displays the server information and will list all the groups that server is in. So below is my basic model layout

class Group(models.Model):
    parent = models.ForeignKey("Group", null=True, blank=True)
    user = models.ForeignKey(User)

    name = models.CharField(max_length=100)
    about = models.TextField(blank=True, null=True)

    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    def __unicode__(self):
        return self.name

class Server(models.Model):
    hostname = models.CharField(max_length=300, db_index=True)
    about = models.TextField(blank=True, null=True)

    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

    groups = models.ManyToManyField(Group)

    def __unicode__(self):
        return self.hostname

So to get all the groups my server is a member of is pretty easy.

s = Server.objects.get(id=1)
s.groups.all()

Now to get all the servers in a group is also easy

g = Group.objects.get(id=1)
g.server_set.all()

Calculate Distance In Mysql with Latitude and Longitude

So you have a whole table full of members or places with latitude and longitude’s associated with them. Just replace the $lat and $lon with the center point you want to find distances from. You can also change the distance<=10 to a number you want to search from. This will limit your results to all results that are under 10 miles from the starting point

SELECT ((ACOS(SIN($lat * PI() / 180) * SIN(lat * PI() / 180) + COS($lat * PI() / 180) * COS(lat * PI() / 180) * COS(($lon – lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance` FROM `members` HAVING `distance`<=’10′ ORDER BY `distance` ASC

View Images like Photos.app

Make sure you have JSON Framework installed first.

This is a continuation of Using threads for a JSON request

So right now we have four rows in our table. Each row has a image. So what if we want to view all the images at once. I really like viewing images at my own time. So I don’t want to use a timer and have them switch. If i want to skip a image I want to skip and if I want to take time to look, I want to look.

I really like how Apple has their Photos.app when you view images. You can slide your finger around to move to new images. So lets replicate this.

So open up your project and we need to create a new view to show our images. So right click on Resources -> Add -> New File. Then you want to create a user Interface and View XIB file. We want to call it picView.xib

So now we want to make a controller for the picView. So right click on Classes -> Add -> New File. And we want to create a new UIViewController subclass. We want to call it picViewController.m

Now we need to create a new a new outlet and a new method to init our view. So double click on picViewController.h and we want it to look like the following.

#import <UIKit/UIKit.h>

@interface picViewController : UIViewController {
	IBOutlet UIImageView *image;
}

- (id)initWithImage:(NSString *)url;

@end

Now we are creating a new init method. Normally we did a initWithNibName and then pass in the url to the image. Lets shake things up and and init our view with a custom method and load the nib in the custom function.

So open up picViewController.m and our initWithImage method will look like this

- (id)initWithImage:(NSString *)url {
    // loading the nib here
    if (self = [super initWithNibName:@"picView" bundle:nil]) {
		// grabbing the image and setting it to our imageview
		image.image = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: url]]];
    }
    return self;
}

Now save the file and double click on picView.xib and load up IB. So we want to add a imageview to our whole view so it looks like the following.

Then we need to change File Owner’s type to picViewController.

Now make the connection from the image outlet we created to the imageview on the view. Also make sure you connect the view to the File’s Owner.

Now that we have our picViewController all done lets create a nice button on the navigation bar for an option to show all images. So open up RootViewController.m and in the viewDidLoad method we add the following.

	UIBarButtonItem *showButton = [[[UIBarButtonItem alloc]
			initWithTitle:NSLocalizedString(@"Show All", @"")
			style:UIBarButtonItemStyleBordered
			target:self
			action:@selector(showAll)] autorelease];
	self.navigationItem.rightBarButtonItem = showButton;

Don’t worry we will create our showAll method later.

Now we need to create a new controller and view for the main view that will control the scrolling of our images.

So right click on Resources -> Add -> New File. Then you want to create a user Interface and View XIB file. We want to call it scrollView.xib

So now we want to make a controller for the scrollView. So right click on Classes -> Add -> New File. And we want to create a new UIViewController subclass. We want to call it scrollViewController.m

Now we need to create a new outlet for our scroll view. So open up scrollViewController.h and add in the following.

IBOutlet UIScrollView *scrollView;

Now save the file and double click on scrollView.xib. Now we want to create a new scroll view in the view. So the way to do this is drag a new UIView on the view that is already there and then change the type to a UIScrollView. It should look like the following.

Now we want to change the File Owner’s type to scrollViewController so it looks like the following

Then we want to create the outlet from the File Owner to the scroll view and then connect the view to the main view.

Now the one thing we want to make sure is our main view isn’t too high. If it is the user will be able to move the view up and down and that isn’t the desired effect. We only want them to flick right and left. 

So click on the View and you want to make the height 460. We will get rid of the navigation bar in code when this loads. If you want to keep the navigation bar you have to make the height even less.

Save the xib file and now lets get to some code.

So the first thing we want to is setup our picViewControntroller class. So open up picViewController.h and we want it to look like the following

@interface picViewController : UIViewController {
	IBOutlet UIImageView *image;
	UIImage *img;
}

@property (nonatomic, retain) UIImage *img;

- (id)initWithImage:(NSString *)url;

@end

So we have our image view outlet. We also have a UIImage that will contain the passed in image from our scroll view controller. We create a new init function to easily pass in the image on init. In that function we will call the init nib method

So now open up viewPicController.m. That whole file should look like this

@implementation picViewController

@synthesize img;

- (id)initWithImage:(NSString *)url {

	// loading the nib here
    if (self = [super initWithNibName:@"picView" bundle:nil]) {
		// grabbing the image and setting it to our imageview
		img = [UIImage imageWithData: [NSData dataWithContentsOfURL: [NSURL URLWithString: url]]];
    }
    return self;
}

- (void)viewDidLoad {
	image.image = img;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	// Return YES for supported orientations
	return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
	[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
	// Release anything that's not essential, such as cached data
}

- (void)dealloc {
	[super dealloc];
}

@end

You can see on the new init, we load the nib and then set the passed in image to img. On our viewDidLoad we set the image to the imageview.

So our picViewController is now complete. Lets move on to the scrollViewController where most of the fun is happening.

So open up scrollViewController.h and make it look like the following. You should already have added he outlet for the scrollview

@interface scrollViewController : UIViewController  {
	IBOutlet UIScrollView *scrollView;
	NSMutableArray *viewControllers; // will contain all the picViewControllers
	NSMutableArray *jsonArray; // will get passed in a JSONarray
}

@property (nonatomic, retain) NSMutableArray *viewControllers;
@property (nonatomic, retain) NSMutableArray *jsonArray;

- (id)initWithJSON:(NSMutableArray *)array; // init method to get the json array
- (void)loadPage:(int)page;  // loads a new picViewController

@end

You will see we need to include a scrollview delegate also. This is so we can handle the movements of the scrollview.

Now save that and open up scrollViewController.m and we need to add our inits in. So yo will need to add the following.

- (id)initWithJSON:(NSMutableArray *)array {
	if (self = [super initWithNibName:@"scrollView" bundle:nil]) {
		// Initialization code
		self.jsonArray = [[NSMutableArray alloc] init];
		self.jsonArray = array;
	}
	return self;
}

Now we need to create a loadPage method. What this method is doing is it is saying load the picViewController into the viewControllers array if it is not already there. We will create this array a bit later so don’t worry about it not being there.

- (void)loadPage:(int)page {
    if (page < 0) return;
    if (page >= [self.jsonArray count]) return;

    // replace the placeholder if necessary
    picViewController *controller = [viewControllers objectAtIndex:page];
    if ((NSNull *)controller == [NSNull null]) {

		// grabbing the image
		NSDictionary *itemAtIndex = (NSDictionary *)[self.jsonArray objectAtIndex:page];

        controller = [[picViewController alloc] initWithImage:[itemAtIndex objectForKey:@"img"]];
        [viewControllers replaceObjectAtIndex:page withObject:controller];
        [controller release];
    }

    // add the controller's view to the scroll view
    if (nil == controller.view.superview) {
        CGRect frame = scrollView.frame;
        frame.origin.x = frame.size.width * page;
        frame.origin.y = 0;
        controller.view.frame = frame;
        [scrollView addSubview:controller.view];
    }
}

So you can see we are loading a new picViewController as long as it isn’t a page more then the the pics we have or less then 0. Then we add it to the scrollview at a set x/y.

So the idea is add page 0 first.. then add the next page to the width of page 0. Add page 2 the width of page 0 + width of page 1. That will give us the effect of scrolling back and forth

Now lets create our viewDidLoad method

- (void)viewDidLoad {
	[super viewDidLoad];

	// hiding the navigation bar
	self.navigationController.navigationBarHidden = YES;

    // view controllers are created lazily
    // in the meantime, load the array with placeholders which will be replaced on demand
    NSMutableArray *controllers = [[NSMutableArray alloc] init];
    for (unsigned i = 0; i < [self.jsonArray count]; i++) {
        [controllers addObject:[NSNull null]];
    }
    self.viewControllers = controllers;
    [controllers release];

    // a page is the width of the scroll view
    scrollView.pagingEnabled = YES;
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * [self.jsonArray count], scrollView.frame.size.height);
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.scrollsToTop = NO;
    scrollView.delegate = self;

    [self loadPage:0];
    [self loadPage:1];
}

So you can see up top I am hiding the navigation bar and loading a array full of nothing. There is a good reason for this. If you have a user that has say 150 images, you don't want to load them all at once. It will kill the app. You want to load things as they are about to be shown. So at the botom we are loading the first page and the next page. This is so we don't want the user to wait to see the image. We want it shown right away.

Now that is down we need our final method for the class. So now lets create a scrollViewDidScroll method. This is part of the UIScrollViewDelegate. This is how we can tell our application a user has scrolled. In our case it will let us know when a user has flicked a finger to the left or right and load the next set of views.

- (void)scrollViewDidScroll:(UIScrollView *)sender {
    // Switch the indicator when more than 50% of the previous/next page is visible
    CGFloat pageWidth = scrollView.frame.size.width;
    int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;

    // load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
    [self loadPage:page - 1];
    [self loadPage:page];
    [self loadPage:page + 1];
}

So based on the current width we can tell what page we are on in the scrollview. Then based on that page load the previous page, current page and next page. Don't worry if you are on page 0, our loadPage method won't be called for a -1 page.

That is all there is to it. I wrote this over 2-3 days so things might be missing. I am sorry for that. You can grab the code here and read through it.

Add a Wiggle

This will be a continuation of Multiple Objects and UITouch

If you do a long touch in the main section of the iPhone on a icon you will notice the icons will wiggle. This shows the user they can be deleted or moved around. So lets try to mimic that as best we can and when we stop a drag of our image it will wiggle for two seconds.

The first thing we need to do is import a framework to our project. So right click on the Frameworks tab. Then click on Add Framework. Then click QuartzCore FramwWork.

So first open up touchViewController.h and we need to add in two function

-(void)doWiggle:(UIView *)touchView;
-(void)endWiggle:(NSTimer*)timer;

Now open up touchViewController.m and we need to add in two functions

-(void)doWiggle:(UIView *)touchView {

	// grabbing the layer of the tocuhed view.
	CALayer *touchedLayer = [touchView layer];

	// here is an example wiggle
	CABasicAnimation *wiggle = [CABasicAnimation animationWithKeyPath:@"transform"];
	wiggle.duration = 0.1;
	wiggle.repeatCount = 1e100f;
	wiggle.autoreverses = YES;
	wiggle.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(touchedLayer.transform,0.1, 0.0 ,1.0 ,2.0)];

	// doing the wiggle
	[touchedLayer addAnimation:wiggle forKey:@"wiggle"];

	// setting a timer to remove the layer
	NSTimer *wiggleTimer = [NSTimer scheduledTimerWithTimeInterval:(2) target:self selector:@selector(endWiggle:) userInfo:touchedLayer repeats:NO];

}

-(void)endWiggle:(NSTimer*)timer {
	// stopping the wiggle now
	[((CALayer*)timer.userInfo) removeAllAnimations];
}

Now that we have two functions. We need add the touchesEnded method that gets called when you lift your finger off the screen.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

	UITouch *touch = [[event allTouches] anyObject];

	if ([touch view] == image) {
		[self doWiggle:[touch view]];

	}
	else if ([touch view] == image2) {
		[self doWiggle:[touch view]];
	}
}

Now your image will wiggle when you end your drag.

You can grab the source code here.

Multiple Objects and UITouch

Here is a bit of a continuation of Working with UITouch

Please follow that tutorial first. We will be using the source code from that as our starting point. So once you have the source code in Xcode open up touchViewController.h and we need to add in one new outlet for our second image.

So we want the file to look like this. I have commented the line I have added in.

#import <UIKit/UIKit.h>
@interface touchViewController : UIViewController {
	IBOutlet UIImageView *image;
	IBOutlet UIImageView *image2; // added this
}

@end

Now we need to open up IB and create the new object and make the connection. Double click on touchViewController.xib. So my view now looks like this

My connections now look like this

Also we need to set something for the views in order for a click and drag to work on them. We need to make sure user interaction is enabled on the two UIImageViews we have in our main view. So the property for one looks like the following. Make sure you set this for both image views

Now you can save your view in IB and load up touchViewController.m. In our previous example we had the following method.

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
	// get touch event
	UITouch *touch = [[event allTouches] anyObject];

	// get the touch location
	CGPoint touchLocation = [touch locationInView:touch.view];

	// move the image view
	image.center = touchLocation;
}

You can now either comment out that function or delete it. We don’t want to use it anymore. Instead add in the following method.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	// get touch event
	UITouch *touch = [[event allTouches] anyObject];
	CGPoint touchLocation = [touch locationInView:self.view];

	if ([touch view] == image) {
		// move the image view
		image.center = touchLocation;
	}
	else if ([touch view] == image2) {
		// move the image view
		image2.center = touchLocation;
	}
}

That function will now allow you to click on a imageview and hold the click and drag the image around the screen.

As always you can grab the source code here.

Access the Address Book

I got a request on how do I access the address book in the iPhone. So I took around 30 minutes to learn how and here is how we will do it. 

First create a new View-Based Application and call it addressBook.

Now the first thing we want to do is setup the 4 IBOutlets and the 1 IBAction for our project. We also need to include the headers for the address book framework. So open up addressBookViewController.h and you want to make it look like the following.

#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
@interface addressBookViewController : UIViewController  {
	IBOutlet UIButton *button;
	IBOutlet UILabel *firstName;
	IBOutlet UILabel *lastName;
	IBOutlet UILabel *number;
}

-(IBAction)getContact;

@end

Now that they are added we need to add in the framework files. So you will right click on the addressBook in the Targets option on the left panel and click on Get Info.

At the bottom there is a + and click that and you need to add the following items in AddressBook.framework and AddressBookUI.framework

Now lets layout our view. So double click on addressBookViewController.xib. You want your view to look like the following.

I used the —–’s just so you can see there is a UILabel there. Now we need to setup the connections for the 4 outlets and the one action. You want it to look like the following

So now lets open up addressBookViewController.m and we want to add in the following methods.

-(IBAction)getContact {
	// creating the picker
	ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
	// place the delegate of the picker to the controll
	picker.peoplePickerDelegate = self;

	// showing the picker
	[self presentModalViewController:picker animated:YES];
	// releasing
	[picker release];
}

- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
    // assigning control back to the main controller
	[self dismissModalViewControllerAnimated:YES];
}

- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {

	// setting the first name
    firstName.text = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);

	// setting the last name
    lastName.text = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);	

	// setting the number
	/*
	 this function will set the first number it finds

	 if you do not set a number for a contact it will probably
	 crash
	 */
	ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
	number.text = (NSString*)ABMultiValueCopyValueAtIndex(multi, 0);

	// remove the controller
    [self dismissModalViewControllerAnimated:YES];

    return NO;
}

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
    return NO;
}

Now we can click build and go and see the following


As always you can grab the source here.

Working with UITouch

So here is a quick post on how to work with a UITouch. This tutorial will put a UIImageView on a view and then when you touch around the image view will be placed where you touch.

So lets start out by creating a new project and and use a View Based application as shown below.

Now I called the project touch.

So lets create an outlet for the image view we will create. So open up touchViewController.h. Add your outlet.
IBOutlet UIImageView *image;

Now take a image and drag it into your project. For this I will use the following image.

Now double click on touchViewController.xib and it will load IB. Take a UIImageView and drag it on the view. You also want to set the image to the image you dragged to your project. Your view should now look something like this

Now create the link from the outlet you created to the view so it looks like this in the File’s Owner.

Now save the file and quit. If you clicked build and go now we will just see a box on the screen and it does nothing. So we need to add in a function to handle the touch.

So open up touchViewController.m and add in the following code.

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
	// get touch event
	UITouch *touch = [[event allTouches] anyObject];

	// get the touch location
	CGPoint touchLocation = [touch locationInView:touch.view];

	// move the image view
	image.center = touchLocation;
}

So pretty much we are grabbing a touch even on any object it may touch. Then we are getting the location of the touch. We will then take that and move the image.

The thing that sent me for a loop is the locationInView accepts a UIView so I was wondering why self.view didn’t work. I still have no clue but touch includes the view that was touched and that seems to work nicely.

The Apple code works off sub-classing your view which I have never done but this seems to work nicely.

As always here is the source code.

Change background of a UITableViewCell

I was asked this question by a co-worker on how to do this. My first answer was when you init the cell just set the backgroundColor but that did not work at all.

If you followed my other tutorials and have a custom UITableViewCell open that file and in the initWithFrame method you want the following

MyContentView.backgroundColor = [UIColor redColor];

Post a UIImage to the web

So here is something a lot of people have been wondering to do in the forums. How do I take a UIImage or any image and post it to a website. So this will go over how to do that.

There are two ways to tackle this issue. One we can base64 encode the file and post is normally inside a XML or JSON instance or we can simulate a normal HTML post. This tutorial will go over the HTML post.

This will start off where Using a UIImagePickerController left off. So you can grab the code and start there if you want. So lets begin.

So first open up testPickerViewController.h and we want to add in one outlet and one action.

So here is the outlet we want to add
IBOutlet UIButton *upload;
Here is the action we want to add
IBOutlet UIButton *upload;
Now double click on testPickerViewController.xib and we need to connect the new outlet and action. We also need to create our new upload button. So drag around the current items and place the new button under the grab button. Then you want to make the button hidden by default. The option is as shown below. Do get to that selector you do Tools -> Attributes Inspector

You might also want to setup your UIImageView to aspect fit. If the image is larger then your box you created in IB it will shrink the image to fill it. Click on the UIImageView and in the Attributes Inspector select the following drop down for Mode

Now you want to make your connections to the new outlet and action we created in code. So here is another screenshot of what they should look like

Now it is back to the code. So save this and you can quit IB. 

So open up testPickerViewController.m and find the imagePickerController method and at the end add 
upload.hidden = NO;

That will show our upload button once a image is set.

So now we need to create our uploadImage method that gets called then the button is pressed. So it is below and hopefully pretty well commented.

- (IBAction)uploadImage {
	/*
	 turning the image into a NSData object
	 getting the image back out of the UIImageView
	 setting the quality to 90
	*/
	NSData *imageData = UIImageJPEGRepresentation(image.image, 90);
	// setting up the URL to post to
	NSString *urlString = @"http://iphone.zcentric.com/test-upload.php";

	// setting up the request object now
	NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
	[request setURL:[NSURL URLWithString:urlString]];
	[request setHTTPMethod:@"POST"];

	/*
	 add some header info now
	 we always need a boundary when we post a file
	 also we need to set the content type

	 You might want to generate a random boundary.. this is just the same
	 as my output from wireshark on a valid html post
	*/
	NSString *boundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"];
	NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
	[request addValue:contentType forHTTPHeaderField: @"Content-Type"];

	/*
	 now lets create the body of the post
	*/
	NSMutableData *body = [NSMutableData data];
	[body appendData:[[NSString stringWithFormat:@"rn--%@rn",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
	[body appendData:[[NSString stringWithString:@"Content-Disposition: form-data; name="userfile"; filename="ipodfile.jpg"rn"] dataUsingEncoding:NSUTF8StringEncoding]];
	[body appendData:[[NSString stringWithString:@"Content-Type: application/octet-streamrnrn"] dataUsingEncoding:NSUTF8StringEncoding]];
	[body appendData:[NSData dataWithData:imageData]];
	[body appendData:[[NSString stringWithFormat:@"rn--%@--rn",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
	// setting the body of the post to the reqeust
	[request setHTTPBody:body];

	// now lets make the connection to the web
	NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
	NSString *returnString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];

	NSLog(returnString);
}

So now if you build and go you will upload the image you selected to the following image URL

http://iphone.zcentric.com/uploads/ipodfile.jpg

Below is my PHP file I am using to handle uploads.

$uploaddir = './uploads/';
$file = basename($_FILES['userfile']['name']);
$uploadfile = $uploaddir . $file;

if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
        echo "http://iphone.zcentric.com/uploads/{$file}";
}

It is nothing special. I do an echo so you can see in the console what the file is. If you switch the filename=”" part in the uploadImage section it will be placed as another file.

Files will be removed once they are 10 minutes old on the server so they won’t last but you can use it as a playground.

As always here is my code.

Using a UIImagePickerController

Apple allows you great access into the images you have taken with your camera or saved on the phone via Safari or such. It also allows you to load up the camera very easily in your code to take pictures from your application.

So the first thing we want to do is start a new project and call it testPicker. You want to create a View based application.

Now that our application is created we want to open up IB and create our view. So double click on the testPickerViewController.xib file and it will launch IB. The first thing you will notice is that is is a blank view. So lets grab a round rectangle button on the view and also a image view controller. So now our view should look something like this

So now we have to create 2 outlets and an action. The outlets are for the items we placed on the view and the action is for the button click. So make sure you are selecting the File’s Owner name and it should be of type testPickerViewController and create 2 outlets and an action. Name them like the following image.

Now we need to connect them. So you just drag the outlet to the correct item on the view and then grab the action over to the button and a box will popup and select touch up inside as an option. It should look like the following

Now we have to write the new class file. Make sure you are still selected to File’s Owner and go to File -> Write Class Files. You should get the following if you did it the correct spot.

Save the file. It will ask you to merge or overwrite. For this just overwrite the files.

Now that we have our view setup, lets do some code. So the first thing is we must set the UIImagePickerController delegates.

So open up testPickerViewController.h and we want to add in the following to the class reference.
UINavigationControllerDelegate, UIImagePickerControllerDelegate>
Now we need to add the reference to our image picker so add the following
UIImagePickerController *imgPicker;
Now we need a property for it.
@property (nonatomic, retain) UIImagePickerController *imgPicker;
So the whole file looks something like this now

@interface testPickerViewController : UIViewController   {
    IBOutlet UIButton *button;
    IBOutlet UIImageView *image;
    UIImagePickerController *imgPicker;
}
- (IBAction)grabImage;

@property (nonatomic, retain) UIImagePickerController *imgPicker;

@end

Now save the file and open up testPickerViewController.m. First we need to synthesize the image picker
@synthesize imgPicker;
Now we need to create the viewDidLoad method and init the image picker.

- (void)viewDidLoad {
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.allowsImageEditing = YES;
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}

There are 3 different types of sources you can use

  • UIImagePickerControllerSourceTypeCamera : to load the camera
  • UIImagePickerControllerSourceTypePhotoLibrary : to load images from library
  • UIImagePickerControllerSourceTypeSavedPhotosAlbum : loads all images saved

Also we set the editing to YES. This will allow your user to crop the image and such. The picker controller’s delegate function we will add later will return the information so you can edit the UIImage that is returned if you really wanted. We will not cover that here. At least not yet.

Now lets load the picker on the button click so make the grabImage method look like this

- (IBAction)grabImage {
[self presentModalViewController:self.imgPicker animated:YES];
}

Now if we click build and go, you will be able to click on the grab images button and your image picker will slide up from the bottom and allow you select a image.

Now we need to add in our delegate methods so we can handle the image when a user selects it. The only one we will really cover is imagePickerController. Here is my complete function to take the selected image and then place it into the imageview we created in IB.

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

Here is our final product.

As always you can grab the code here.

Next Page »