Blog Archives

Asset Libraries and Blocks in iOS 4

iOS 4 presented a million billion new API’s by Apple’s count, but for this post I am going to show a quick demo of the new Assets Library API where you can now get to users photos and videos with more access than ever before. This new API relies on the new programming device called Blocks that has been introduced with iOS 4. Blocks are used through many of the new API’s as a kind of extended @selector. We will look into this new development device and make a small project to create our own UIImagePickerController. In the end we are going to create a tableview that is filled with all the photos within our library. Check out the video below or follow the steps typed out below.

Screencast

Using the Assets Library API in iOS 4 from Collin Ruffenach on Vimeo.

Creating the Project

Create a new project in xCode. Make it for the iPhone since this is an iOS 4 framework. A view based application will create a view controller for us, so lets use that. Call your project MyImagePicker.

Adding in the framework

This project will revolve around taking advantage of the AssetsLibrary framework introduced with iOS 4. Due to this you must have the newest xCode and iPhone SDK installed with iOS 4.0 support. If this is done you should be able to expand the frameworks folder of your project. Right click on UIKit.framework and select “Reveal in Finder”. This will open up the folder that contains all of the frameworks you can use in an iOS 4 project. Find AssetsLibrary.framework and drag into the Frameworks folder of your project. Once dragged in make sure that the Copy items into destination folder options is deselected and that it is set to recursively create groups for any added folders.

Using the framework with blocks

iOS 4.0 introduces a totally new programming concept for Objective C developers to take advantage of when creating their own code and when using Apple’s API. Blocks in the most simple terms are Objective C objects that are methods. A block uses the special character ^ to denote its beginning and is a required parameter of many of the API’s introduced within iOS 4.0. Apple has some great documentation on blocks, and how they conceptually fit into the current objective C landscape. You can see their concise but effective overview here. For our purposes I am just going to review the simple syntax of a block.

Before we dive into blocks lets take a look at the AssetsLibrary framework methods that will require them. The general flow of the object access we will be doing is as follows.

We are going to create an ALAssetsLibrary and call a method on it that will enumerate through all the ALAssetsGroups it has access to. For every ALAssetsGroup we will call a method on it which will enumerate through the ALAssets it has access to. We will save each ALAsset into an array we will use to populate our tableview. The two different enumerations we are going to perform is where the blocks will come in. But lets first set up our view controller appropriately.

MyImagePickerViewController.h

#import <UIKit/UIKit.h>;
#import <AssetsLibrary/AssetsLibrary.h>;
@interface MyImagePickerViewController : UIViewController {
 
	IBOutlet UITableView *tableview;
	IBOutlet UIActivityIndicatorView *activity;
 
	NSMutableArray *assets;
}
 
@property (nonatomic, retain) IBOutlet UITableView *tableview;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activity;
 
@end

We are going be using the assets array here to hold the assets that we are going to pull using the AssetsLibrary Framework.

Now open up MyImagePickerViewController.xib and drag in a UITableView and a UIActivityIndicatorView. With these in place connect them to the IBOutlets you created for this class. Also make sure to connect the UITableViewDataSource and UITableViewDelegate to the MyImagePickerViewController as well. With that done we can start to use the AssetsLibrary Framework.

Using the Asset Library

Now we are going to use our AssetsLibrary framework. This will be done within the viewDidLoad method of your MyImagePickerViewController.m. Put the following code in there.

1 - (void)viewDidLoad {
2
3    [super viewDidLoad];
4    [activity startAnimating];
5
6    void (^assetEnumerator)(struct ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
7	if(result != NULL) {
8		NSLog(@"See Asset: %@", result);
9		[assets addObject:result];
10
11	}
12    };
13
14    void (^assetGroupEnumerator)(struct ALAssetsGroup *, BOOL *) =  ^(ALAssetsGroup *group, BOOL *stop) {
15	if(group != nil) {
16		[group enumerateAssetsUsingBlock:assetEnumerator];
17	}
18
19
20	[self.tableView reloadData];
21	[self.activity stopAnimating];
22	[self.activity setHidden:YES];
23    };
24
25    assets = [[NSMutableArray alloc] init];
26    library = [[ALAssetsLibrary alloc] init];
27    [library enumerateGroupsWithTypes:ALAssetsGroupAlbum
28					   usingBlock:assetGroupEnumerator
29					 failureBlock: ^(NSError *error) {
30						 NSLog(@"Failure");
31					 }];
32 }

We are going to be going though this code line by line. On line 4, we start animating our activity indicator. I will explain why we have to do that a little bit later. Lines 6 – 23 are the lines that will  declare the two blocks that we will use to fill our tableview with pictures. We are going to declare two blocks to use as parameters to methods within a ALAssetLibrary object and a ALAssetGroup object. The first method call we will make will be on our ALAssetLibrary object. So for the moment lets skip passed the block declarations and look at line 25. On line 25 we instantiate our NSMutableArray to hold the ALAssets that we will pull out from the AssetsLibrary. On line 26 we will create our ALAssetsLibrary object. We will call a single method on this object to loop through all of the assets in a library. The method is:

– enumerateGroupsWithTypes:usingBlock:failureBlock:

This method takes in 3 parameters. An ALAssetGroup type, a block to be performed on each group and a block to be performed on failure. Lets talk about block syntax. A block is a native Objective C object. It is a subclass of NSObject. With that said it is also an Objective C method. An objective C method is composed of three things. A return type, a parameter list and a piece of code to be executed. We are going to pass the assetsGroupEnumerator block object that declare on line 14 into this method. Lets take a look at how the block is declared.

You begin by specifying a return type for the block. Void in this case. Next you enclose a name for the block which is proceeded by a carrot ^ character. This is the special character Apple has decided on to denote blocks. You begin block names with blocks as well as the actual declaration of what a block is. This name is wrapped in parenthesis. This is followed by the parameter list that the block will accept. In this case it is a ALAssetsGroup object and a Boolean indicating whether to stop. Now I did not come up with these parameters by myself. Since I will be passing this block into an ASAssetLibrary the documentation will tell us what will be passed into the block. ALAssetsLibrary objects documentation can be seen here. With that all said, lets take a look at the code that will actually compose this block. Starting on line 15 we will make sure that we are seeing a valid group. If the ALAssetsGroup object that we are passed is valid then we will call another enumeration on the group which will enumerate through assets. This enumeration method also requires a block. We declared this block above. This block is called assetEnumerator. Once again we retrieved the parameters list from the documentation of the object asking for, in this case an ALAssetsGroup.

For this block, which begins on line 6, the block is passed an ALAsset object, an index and a stopping condition boolean. Within the code of the block we will ensure that the returned ALAsset is valid and if it is we will add it to our array which will hold all of our assets. With this block declared we pass it into the call to our ALAssetsLibrary object on line 16.  Once every group has been enumerated and our array is filled with all of our ALAssets we will tell the tableview to reload its data and get rid of our UIActivityIndicatorView.

With all of this done all that remains if filling in the required UITableViewDataSource methods. The tableview will be filled with the assets we collected. ALAsset objects are cool in that they include a method called -thumbnail which returns a CGImageRef to a thumbnail we will use. I won’t explain the development of these methods any further since they are pretty straight forward.

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}
 
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [assets count];
}
 
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
 
	ALAsset *asset = [assets objectAtIndex:indexPath.row];
	[cell.imageView setImage:[UIImage imageWithCGImage:[asset thumbnail]]];
	[cell.textLabel setText:[NSString stringWithFormat:@"Photo %d", indexPath.row+1]];
 
    return cell;
}

iOS 4: Exchange Mail, Contacts, or Calendars may not sync after update

I know you guys have iPhones, this may be interesting for you.  If you know anyone else using iPhones with Exchange server, you might want to read this:

support.apple.com/kb/TS3398

Adding TwitPic to your Application

Introduction

Back in July of last year. Brandon put up a post showing you how to integrate twitter into your application. Today I am going to take the class he made last year and add a new class which will let you post to twit pic. First lets do a little overview of what tools we need for this.

Required Tools

Twit pic is an awesome service. They have created a whole public API, that anyone can use to host a picture and post a tweet with a link to it. You can see the TwitPic API, and all its functionality here.The API is pretty simple, with only 2 methods.

  • uploadAndPost
  • upload

We are going to only be implement access to the uploadAndPost method. In order to use the API we need to use an HTTP POST method. While Apple provides NSURLConnection to take care of operations like this, we are going to use a better third party framework called ASIHTTPRequest. You can find ASIHTTPRequest to download here. I will go over the steps to get it installed. Just download the files for right now. You will also need to download some utility files that Apple created for users called Reachability. You can find those files here.

Preparing a project to use ASIHTTPRequest

  1. Before we add the method into out TwitterRequest class, we have to do a bit of preparation with a project we want to use this framework witb. First think to do is to add ASIHTTPRequest and the Reachability classes into your application.
  2. Now we have to add some frameworks to out project by “Editing the active target”. Go to Project ->  Edit Active Target “TwitPic”
  3. Add in the following targets: CFNetwork.framework, SystemConfiguration.framework and libz.1.2.3.dylib

Using ASIHTTPRequest to contact TwitPic

Now if we compile we should see no errors, and we will be able to use ASIHTTPRequest in our new method in out TwitterRequest class. The method to communicate with TwitPic is actually going to be very short. We need to create the method to send the picture and fill in the methods to handle the response. Lets take a look at what these methods look like.

Method to send picture to TwitPic

Here we are going to pass in the photo for twit pic along with the delegate that is using out class. This pertains back to the design decision made when developing the original TwitterRequest class. Look back at the first post for expansion on this. Here we create an instance of an ASIFormDataRequest. request is an instance variable I declared in the TwitterRequest header. Pass in the proper values for the proper keys, following along with the TwitPic API. We are going to start and Asynchronous request here, so the UI does not freeze while the picture is being uploaded.

-(void)statuses_update:(NSString *)status withPhoto:(NSData*)photoData delegate:(id)requestDelegate requestSelector:(SEL)requestSelector {
     isPost = YES;
     // Set the delegate and selector
     self.delegate = requestDelegate;
     self.callback = requestSelector;
     // The URL of the Twitter Request we intend to send
     NSURL *url = [NSURL URLWithString:@"http://twitpic.com/api/uploadAndPost"];
     // Now, set up the post data:
     request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
     [request setDelegate:self];
     [request setData:photoData forKey:@"media"];
     [request setPostValue:username forKey:@"username"];
     [request setPostValue:password forKey:@"password"];
     [request setPostValue:status forKey:@"message"];
     // Initiate the WebService request
     [request startAsynchronous];
}

Methods to handle response

We need to handle two types of response from TwitPic. Either the request will finish, or the request will error. If the request finishes the following will be called. We check that the delegate set for the TwitterRequest class is present and that is responds to the selector that was passed in. If it does, the TwitterRequest class will respond back to the class using it.

- (void)requestFinished:(ASIHTTPRequest *)request {
NSLog(@"%@", [request responseString]);
// do something with the data
     if(delegate && callback) {
          if([delegate respondsToSelector:self.callback]) {
               [delegate performSelector:self.callback withObject:receivedData];
          } else {
               NSLog(@"No response from delegate");
          }
     }
// release the connection, and the data object
     [request release];
}

This is the class that should be used to handle errors. This for example could display a UIAlertView saying that an error occurred.

- (void)requestFailed:(ASIHTTPRequest *)request {
     NSError *error = [request error];
}

You can download the Header and Main for the updated TwitterRequest class here.

Murphy’s laws for woodworkers

I’m pretty jazzed about a couple of design classes slated for this upcoming year. First up is a weekend workshop at the Marc Adams School of Woodworking this June 26th and 27th. If you are feeling the itch to begin creating your own designs, this might be a great way to try the water. Rest assured you will learn some of the basics on proportions, forms, the classic orders, but this class is really about learning to see and visualize. I’m working hard to put together a program that is inspiring and at the same time down to earth and practical at your workbench. Something else you should know before signing up. I like to have fun and try not to take myself too seriously. Come prepared not only to learn about design but also share a few laughs. Speaking of which, I dug this out from the last class I taught at MASW along with Dr Tom Young a few years ago. It’s sort of a collection of woodworking proverbs or Murphy’s laws of woodworking. Many of these I have learned the hard way:

  1. Off square parts will assemble for maximum ill effect.
  2. Your workshop is never big enough.
  3. The workshop of your dreams won’t be big enough.
  4. Mobile bases aren’t mobile in seven inches of sawdust.
  5. Plastic wood isn’t.
  6. A Safety guard hasn’t been invented that can prevent stupid.
  7. Sawdust coating the laundry basket usually precedes a storm.
  8. Finding one of your good chisels in the kitchen junk drawer is another sign of an impending storm.
  9. The ideal number of clamps is two more than you will ever own.
  10. The ideal sized clamp is two inches longer than the one you are making do with.
  11. It’s time to sweep the shop floor when:
    1. You start losing tools bigger than a router.
    2. The kids start digging tunnels and building forts.
    3. You start bumping your head on the ceiling.
  12. Amateur woodworkers don’t have clocks in their workshops; professionals don’t have enough time in theirs.
  13. Hammering a bent nail into a board will not make it go away.
  14. A tool tray at the back of your workbench was the original inspiration for the discovery of “Black holes” in the universe.
  15. The original cost of a router is insignificant compared to what you will spend on router bits.
  16. The amount of years spent woodworking is directly proportional to the amount of extra lights and outlets installed in the workshop.
  17. Flying objects are never a good sign in the workshop.
  18. Smoke is never a good sign in the workshop.
  19. A popping sound when removing clamps is never a good sign in the workshop.
  20. Re-attached fingers never work as well as original equipment.
  21. Lumber always costs more than you planned.
  22. You never have enough tools until you have at least three of everything.
  23. “Natural material – no two are alike” means this wood is full of knots.
  24. Your biggest goof will take place nearest the end of a project.
  25. Experienced woodworkers still make mistakes; they are also more adept at hiding them.
  26. All blueprints contain errors; it’s your job to find them the hard way.
  27. There are six different ways to solve any woodworking problem, and at least thirty six ways to flub it up.
  28. Calling it a day after really screwing something up will not make it better in the morning.
  29. A dull drill bit will not magically become sharp by throwing it back in a cigar box.
  30. If you never scrap anything, you probably don’t make anything either.
  31. No one appreciates a door that closes smoothly, but even a moron will crab about one that sticks.

 

I’ve been compiling this list for some time. If you have any to add, I’d love to hear them.

George R. Walker

The 19 most complex and dangerous roads in the world

Sure, it feels fantastic to traverse the vast stretches of the best roads in the world via adrenaline pumping speeds. How about a complicated road, one that twists and turns, or has downright congested traffic, or unforgiving terrain? They might give you a headache, but it sure feels good when you’ve conquered them. Here is the  list of the world’s most complicated and dangerous roads. Some of these complicated mountain passes can be dangerous if not negotiated with utmost caution, while others are complicated sets of roads and bridges, erected to ensure a streamlined flow of traffic at busy junctions. Without further ado, we present our top 19 list…

1) Col de Turini, France

Col-De-Turini-1

Col-De-Turini-2

photo credits : 1,2

Situated more than 1 mile above sea level, Col de Turini is a mountain pass situated in south of France in the Alps. It’s also part of a 20 miles rally stage of the Monte Carlo Rally of WRC, which combines 34 challenging hairpins and long stretches where cars top 111 mph. It is one of the most exciting roads on Earth.  The pass was featured in the very first episode of Top Gear series 10, when the presenters went in search of the greatest driving road in the world. At its highest point, Col de Turini  is 1607m high. In the north, the Col de Turini starts  with a dazzling series of hairpins. Finally, we end up riding in a gorge, with a wild river on the left, and a steep rock-wall on the right.

2) Stelvio Pass, Italy

stelvio-pass

stelvio-pass-north-ramp

Photo credits 1,2

Located in the Eastern Alps in Italy, the Stelvio Pass Road connects the Valtellina with Merano and the upper Adige valley. This mountain road pass is situated at an altitude of around 1.7 miles above sea level. The road is particularly challenging to drive due to the presence of 48 hairpin bends, with the road becoming exceedingly narrow at some points, and some very steep inclines. With a height of 2757 meters, it is the highest paved mountain pass in the Eastern Alps and the second highest in the Alps, after the 2770 m high Col de l’Iseran. While it might not be as dangerous  as the other routes, it is certainly breathtaking. The  toughest and most spectacular drives are from the Prato side. The mountain pass is  one of the best continuous hairpin routes in the world.

3) Leh–Manali Highway, India

leh-manali-highway

Photo credit 1

The Leh-Manali Highway is situated in India and spans over a length of 297 miles among the Himalaya mountain range. It passes through some of the worlds highest mountain passes in the world, with a mean altitude in between 2 to 3 miles above sea level. The road is one of the most complicated and challenging roads in the world, with snow, landslides and terrain making the journey exceedingly difficult for anything other than a capable four wheel drive vehicle. The road was built and is maintained by the Indian Army.

4) The Puxi Viaduct, Shanghai

Puxi Viaduct_Shanghai2

Photo credit 1

This is one of Shanghai’s busiest and largest interchange that caters to thousands of vehicles every hour. It has five levels of bridges that help connect two of the cities busiest highways, directing vehicles without much fuss.

5) The Judge Harry Pregerson Interchange, LA

The-Judge-Harry-Pregerson-Interchange

Photo credit: 1

The Judge Harry Pregerson Interchange is situated in Los Angeles, CA and is one of the most complicated interchanges in the country. It permits entry and exit in all directions between the I-105 and the I-110. It’s a stack interchange with layers of bridges making a complicated network of roads allowing smooth flow of traffic though both the interstate highways. This interchange was opened in 1993. It is a 4 level interchange with a restricted access lane that can be used by high-occupancy vehicles.

6) The Road of death, Bolivia

road of death2

Photo credits:  1, 2

The North Yungas Road (also known as the El Camino de la Muerte, ‘Road of Death’ in Spanish) is a 43 mile road connecting La Paz and Coroico, 35 miles northeast of La Paz in Bolivia. Famous for its extreme danger, it was christened as the “world’s most dangerous road” in 1995 by the Inter-American Development Bank. The single-lane width, extreme drop offs, and lack of guardrails, only add to the danger lurking behind. Further, the fog and rain can make visibility poor and the road surface muddy, loosening rocks from the hillsides above. It is estimated that 200 to 300 travelers are killed per year on this treacherous road. Although, the old North Yungas Road is  much less used by traffic nowadays, an increasing number of adventure bikers  travel it for the thrills.

7) Russia’s Lena Highway, the Highway from Hell

russian-siberian-road-rain

russian-siberian-road-winter

Photo credits: 1,2

The last 600 miles of the Russian Federal Highway from Moscow city to the Siberian city of Yakutsk is called the “Lena Highway”. This bizarre road runs parallel to the River Lena on the final leg to Yakutsk. As if the road of mud was not a big problem, Yakutsk is considered one of the the coldest cities on earth, with January temperatures averaging -45 °F. But surprisingly, it is only in the summertime that the road becomes impassable. Whenever it rains in summer, the road virtually becomes a slush pit making it impossible for the vehicles to pass through it. This being the only road to Yakutsk makes the traffic heavy and even more complicated to negotiate.

8. Gravelly Hill Interchange, Birmingham, UK

burmingham

Photo credit: 1

Gravelly Hill Interchange, nicknamed ‘the Spaghetti Junction’, is the 6th junction  of the M6 motorway, where it joins the A38 Aston Expressway in Birmingham, UK. The name “Spaghetti Junction” was coined by Roy Smith, a journalist from the Birmingham Evening  Mail in the 1970s. The areal view of the junction sure tells us why it is called the Spaghetti Junction. Spanning an impressive 30 acres, the junction serves 18 routes and includes 4 km of slip roads. Across 6 different levels, there are 559 concrete columns, reaching up to 24.4 m in height. The engineers had to elevate 13.5 miles of the motorway to accommodate 2 railway lines, 3 canals, and 2 rivers. It’s the most complicated junction in United Kingdom.

9) Russian-Georgian “Military” Mountain Roads

russia-georgia-military-hiway

Russian-Georgian-Military-Mountain-Roads

Photo credit 1

When they are not covered in sheets of snow, then it’s the thick, grueling mud. These remote highways would probably swallow your car in the snow or mud. Though neither affect the locals who drive their Lada cars down it regularly. Situated in the Caucasus mountains, these roads are to be tackled only by the Russian military which probably explain why they lack any official designation. The harsh surface, along with the problems posed by snow, makes this road almost inaccessible during winter. The seldom used road connects Russia and Georgia and assumes of strategic importance for both countries.

10) Guoliang Tunnel Road, China

Guoliang-Tunnel-1

Guoliang-Tunnel-2

Guoliang-Tunnel-3

Photo credits: 1,2

The magnificent tunnel road in the Taihang mountains was built by 13 local villagers headed by their chief, Shen Mingxin, and took around five years to finish. Many villagers lost their lives in accidents during construction of the tunnel but the others continued relentlessly. The tunnel was opened to traffic on May 1st, 1977. The 1200 meter long tunnel is about 5 meters high and 4 meters wide. It is located in the Henan Province of China. The Guoliang tunnel is another addition to most dangerous and complicated roads to travel. Dubbed as “the road that does not tolerate any mistakes”, most accidents in the tunnel are primarily caused by the neglect of the traveler. Nonetheless, it is an extremely scenic route and is a key destination on the Chinese tourism map.

11) Taroko Gorge Road in Taiwan (Chungheng)

Taroko Gorge Road in Taiwan (Chungheng)-1

Taroko Gorge Road in Taiwan (Chungheng)

Photo credit: 1

The Taroko Gorge Road in Taiwan is another mountain route  made by carving out rocks, like the Guoliang Tunnel road. The road passes through the Taroko national park alongside the Taroko Gorge. The road is an appeal to the tourist, as well as a mode of transportation of marble found abundantly in the Gorge.

12) Pasubio (Vicenza), Northern Italy

Pasubio (Vicenza), Northern Italy1

Pasubio (Vicenza), Northern Italy2

Photo credit: 1

This is a hiking trail made out of an ancient road trail. The road serves mostly for motorcycles and certain types of car. The road is dangerously narrow and slippery, spanning many cliff faces and tunnels with stunning scenery, making this a popular destination for adventurous travelers.

13) The Halsema Highway in the Philippines

Halsema Highway1

Halsema Highway2

Halsema Highway3

photo credits 1

The Halsema Highway runs through the Central Cordillera Valley in Philippines. It is also called the Baguio-Bontoc Road. The road is approximately 150 miles long and is mostly unpaved. The road runs through steep cliff faces which barely have any guard rails or other safety devices installed. The narrow roads and steep cliff faces make the road almost impassable during the rainy season. It’s known for the rock slides and mud slides and buses driving dangerously fast on its narrow passage. There are plenty of accidents and many overturned buses on a yearly basis. There are sheer drop offs of more than 1000 feet without a safety guard rail. This route is for sure one of the most dangerous roads in the world.

14) Trollstigen in Norway

Fjord Roads1

Fjord Roads 2

Photo credts: 1,2

The Fjord in Norway has many roads that attract tourists. The most notable among them is the Trollstigen which is a series of stunning roads with a breathtaking view of a few waterfalls. The word Trollstigen means the Troll Ladder. The road, though not lacking in safety standards, takes a lot of concentration and driving skill to conquer. The vertigo-inducing steep inclines, intense set of hairpins and narrow roads leave no margin for error. However, once you are at the top, the view is just breathtaking. The narrow road leaves us with extremely few possibilities for vehicles to pass each other. The frequent rockfalls in the region have resulted in some upgrades to the road in 2005. At the top, there is a viewing balcony which overlooks the road and the Stigfossen waterfall, a 320 m long waterfall which falls down the mountain side.

15) Los Caracoles Pass in Andes

Los Caracoles1

Los Caracoles2

Photo credit: 1

This road passes though the Andreas Mountains on the way between Chile and Argentina. Los Caracoles is a series of hard switchbacks on an extremely steep incline. The road has many steep inclines and hairpins without any safety guard rails. The road is covered with snow for the most part of the year. The snow together with nature of the road requires extreme patience and skill to negotiate. However, this road is maintained pretty regularly and does not have a morbid accident record. Cargo trucks and even double-Decker tourist buses travel through the road on a daily basis, and it’s quite an experience.

16) Iroha-zaka winding road, Japan

Irohazaka Winding Road Japan

Iroha-zaka winding road is the main route that connects central Nikko and Oku-Nikko. The First Iroha-zaka is used to come down, and the  Second Iroha-zaka to go up. Each corner has an ancient Japanese alphabet, and you will see it in alphabetical order starting from I-ro-ha and hence the name. The road was used by ascetics in the past. The number of curves on the road was 48, matching the 48 letters of the ancient Japanese alphabet. Therefore, the tourist guides started to call the slope Iroha-zaka.  After the construction of the second Iroha-zaka there were 50 curves, but 2 were decreased to remain corresponding with the 48 letters. How’s that for complicated?

17) Van Zyl’s Pass, Namibia

Van Zyl pass

Van Zyl pass1

Van Zyl pass2

Photo credits: 1

Van Zyl’s Pass, or the DR3703, located in Namibia, is a classic extreme road. It is not exactly a road, just a route made over the mountain by the travelers over time. The outrageously steep pass provides a pure adrenaline rush, but the route that leads up to it is a 10-15km of tough driving where one has to dodge their way through rocks, boulders, badlands and ravines. At the end, the road descends to the ancient glacial valley called Marienfluss valley, which is one of the planet’s most beautiful sights that await only the brave-hearted.

18) El Espinazo Del diablo, Mexico

El Espinazo del diablo1

El Espinazo del diablo2

El Espinazo del diablo

Photo credits: 1, 2

El Espinazo Del diablo or ‘The devil’s backbone’ is the mountain pass in Durango, Mexico. It’s about 5 hours long, and it was the only road from Durango to Mazatlan Sinaloa for a long time. We have heard many cautionary tales about crossing the devil’s backbone, El Espinoza Del Diablo, But the road is exceptionally well maintained and there are many cautionary signs marking most of the hazards. Of course these are in Spanish, so keep an electronic translator or a dictionary, handy. Pull out spots are frequent, so you can easily stop anytime you want. There are some tight curves, too. So tight that a truck needs all of the road to make it around. These hinder potential two way traffic in these regions. However, stunning rock formations rising around you and the lush, green vistas stretching on for impossible distances make every inch of the drive breathtaking.

19) Lysebotn Road, Norway

Lysebotn Road

Photo credit: 1

This is probably the most fun road you can travel on four wheels, and then maybe on your two legs checking out the various hiking trails leading from the area. In fact, this might be considered the most breathtaking place in Europe. It all starts with the narrow road up the steep walls of the Lysefjord, Norway. It has 27 switchbacks and a 1.1 km long tunnel at the bottom, with 3 switchbacks inside. The last 30 km of Lysebotn road is a true roller-coaster! It’s narrow but has a perfect surface, winding left and right all the time. If you happen to ride a motorcycle in Norway, then this is the road you simply cannot afford to miss!

Introduction to MapKit in iPhone OS 3.0 Part 2

Introduction

Back in September I posted a large post going over all the components required to implement the MapKit in your application. The MapKit is a framework introduced in iPhone OS 3.0 and allows developers to easily take advantage of Google’s mapping technology. In my first post I go over how to present a map as well as annotate the map with custom badges to highlight points of interest. The MapKit also gives developers access to reverse geocoding services from Google which I will cover in this post.

Reverse Geocoding

A users location is defined by coordinates. When using the Core Location services, or specifying where a map should center its view, coordinates will be the units developers will be working with. This is all well and good for presenting mapping information visually but there is a whole other set of information that can be derived from a set of coordinates.

  • Country
  • State
  • Zip Code
  • Address

Google provides the service to translate any coordinate set to an MKPlacemark object. An MKPlacemark object contains properties to access all this information. Let’s look into the process of getting this object.

Step 1

The first thing you need to do is make a “View Based Application”. Now we need to is pick a set of coordinates we want to use. I have decided to use the address of Arizona State University.

Longitude: -111.936619;

Latitude: 33.416199;

Make your AppDelegates .m file look like this:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Override point for customization after app launch
    [window addSubview:viewController.view];
    [window makeKeyAndVisible];
 
	CLLocationCoordinate2D coord;
	coord.longitude = -111.936619;
	coord.latitude = 33.416199;
 
	MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc] initWithCoordinate:coord];
	[geocoder setDelegate:self];
	[geocoder start]
}

Step 2

Now we need to implement the MKReverseGeocoderDelegate methods. There are only 2 delegate methods:

Called when an error occurs when fetching the reverse geocoder object

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error

Called when the ReverseGeocode object is successfully returned.

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark

Step 3

Now we have a MKPlacemark object to use. An MKPlacemark object conforms to the MKAnnotation protocol. So these objects could be added as annotations to an MKMapView. For more information on MKAnnotations reference part 1. The MKPlacemark object contains the following properties that you can access to use in your application.

To see all of these values make the success delegate method look like this:

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
	NSLog(@"The geocoder has returned: %@", [placemark addressDictionary]);
}

You should see this output:

2009-12-22 11:23:05.492 ReverseGeocoder[2591:207] The geocoder has returned: {
    City = Tempe;
    Country = "United States";
    CountryCode = US;
    FormattedAddressLines =     (
        "200-206 E Lemon St",
        "Tempe, AZ 85281",
        USA
    );
    State = Arizona;
    Street = "200-206 E Lemon St";
    SubAdministrativeArea = Maricopa;
    SubThoroughfare = "200-206";
    Thoroughfare = "E Lemon St";
    ZIP = 85281;
}

Introduction to MapKit in iPhone OS 3.0

Introduction

Hello everyone. Welcome to another screencast. Today we will be looking into the MapKit, a new API’s made available by Apple in the iPhone OS 3.0 release. The MapKit allows simple access to the map seen in the maps application. Using GoogleMaps as its engine the map kit allows for a developer to make their own custom map interface to fit their own application. Today we will be reviewing the MapView as well as the Map Annotations that can be used to highlight points of interest in a map. We will create our own custom map app, along with custom annotations. Let’s dive in.

Skill Level Intermediate

This tutorial is one for people familiar with general Objective C development and introductory experience to the iPhone SDK. Knowledge of general Interface Builder usage and DataSource and Delegate methods are required.

Screencast

I film myself coding out the entire sample project for each post. I personally think going through the Screencast is the best way to learn. But feel free to look through the slides and text if that suites you better.

Introduction to Map Kit on iPhone OS 3.0 from Collin Ruffenach on Vimeo.

Source

iCodeBlogMap Source

Tutorial

Introduction to MapKit on iPhone OS 3.001

Introduction to MapKit on iPhone OS 3.002

Introduction to MapKit on iPhone OS 3.003

Introduction to MapKit on iPhone OS 3.004

Introduction to MapKit on iPhone OS 3.005

Introduction to MapKit on iPhone OS 3.006

Introduction to MapKit on iPhone OS 3.007

Introduction to MapKit on iPhone OS 3.008

Introduction to MapKit on iPhone OS 3.009

Introduction to MapKit on iPhone OS 3.010

Introduction to MapKit on iPhone OS 3.011

Introduction to MapKit on iPhone OS 3.012

Introduction to MapKit on iPhone OS 3.013

Introduction to MapKit on iPhone OS 3.014

Introduction to MapKit on iPhone OS 3.015

Introduction to MapKit on iPhone OS 3.016

Introduction to MapKit on iPhone OS 3.017

Introduction to MapKit on iPhone OS 3.018

Introduction to MapKit on iPhone OS 3.019

Introduction to MapKit on iPhone OS 3.020

Introduction to MapKit on iPhone OS 3.021

Introduction to MapKit on iPhone OS 3.022

iCodeBlogMapViewController.h

#import "iCodeBlogAnnotation.h"
#import "iCodeBlogAnnotationView.h"
 
@interface iCodeMapViewController : UIViewController
{
	IBOutlet UITableView *tableview;
	IBOutlet MKMapView *mapView;
	IBOutlet UIImageView *shadowImage;
}
 
@property (nonatomic, retain) IBOutlet UITableView *tableview;
@property (nonatomic, retain) IBOutlet MKMapView *mapView;
@property (nonatomic, retain) IBOutlet UIImageView *shadowImage;
 
-(void)loadOurAnnotations;
 
@end

Introduction to MapKit on iPhone OS 3.023

iCodeBlogAnnoation.h

typedef enum {
	iCodeBlogAnnotationTypeApple = 0,
	iCodeBlogAnnotationTypeEDU = 1,
	iCodeBlogAnnotationTypeTaco = 2
} iCodeMapAnnotationType;
 
@interface iCodeBlogAnnotation : NSObject
{
	CLLocationCoordinate2D coordinate;
	NSString *title;
	NSString *subtitle;
	iCodeMapAnnotationType annotationType;
}
 
@property (nonatomic) CLLocationCoordinate2D coordinate;
@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *subtitle;
@property (nonatomic) iCodeMapAnnotationType annotationType;
 
@end

Introduction to MapKit on iPhone OS 3.024

Introduction to MapKit on iPhone OS 3.025

Introduction to MapKit on iPhone OS 3.026

iCodeBlogAnnoation.m

@implementation iCodeBlogAnnotation
 
@synthesize coordinate;
@synthesize title;
@synthesize subtitle;
@synthesize annotationType;
 
-init
{
	return self;
}
 
-initWithCoordinate:(CLLocationCoordinate2D)inCoord
{
	coordinate = inCoord;
	return self;
}
 
@end

Introduction to MapKit on iPhone OS 3.027

iCodeBlogAnnoationView.h

@interface iCodeBlogAnnotationView : MKAnnotationView
{
	UIImageView *imageView;
}
 
@property (nonatomic, retain) UIImageView *imageView;
 
@end

Introduction to MapKit on iPhone OS 3.028

Introduction to MapKit on iPhone OS 3.029

Introduction to MapKit on iPhone OS 3.030

Images to Use

AppleMarker

SchoolMarker

TacosMarker



iCodeBlogAnnoationView.m

#import "iCodeBlogAnnotationView.h"
 
@implementation iCodeBlogAnnotationView
 
@synthesize imageView;
 
#define kHeight 40
#define kWidth  37
#define kBorder 2
 
- (id)initWithAnnotation:(id )annotation reuseIdentifier:(NSString *)reuseIdentifier
{
	iCodeBlogAnnotation* myAnnotation = (iCodeBlogAnnotation*)annotation;
 
	if([myAnnotation annotationType] == iCodeBlogAnnotationTypeApple)
	{
		self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];
		self.frame = CGRectMake(0, 0, kWidth, kHeight);
		self.backgroundColor = [UIColor clearColor];
 
		imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AppleMarker.png"]];
		imageView.frame = CGRectMake(kBorder, kBorder, kWidth - 2 * kBorder, kWidth - 2 * kBorder);
		[self addSubview:imageView];
	}
 
	else if([myAnnotation annotationType] == iCodeBlogAnnotationTypeEDU)
	{
		self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];
		self.frame = CGRectMake(0, 0, kWidth, kHeight);
		self.backgroundColor = [UIColor clearColor];
 
		imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"SchoolMarker.png"]];
		imageView.frame = CGRectMake(kBorder, kBorder, kWidth - 2 * kBorder, kWidth - 2 * kBorder);
		[self addSubview:imageView];
	}
 
	else if([myAnnotation annotationType] == iCodeBlogAnnotationTypeTaco)
	{
		self = [super initWithAnnotation:myAnnotation reuseIdentifier:reuseIdentifier];
		self.frame = CGRectMake(0, 0, kWidth, kHeight);
		self.backgroundColor = [UIColor clearColor];
 
		imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"TacosMarker.png"]];
		imageView.frame = CGRectMake(kBorder, kBorder, kWidth - 2 * kBorder, kWidth - 2 * kBorder);
		[self addSubview:imageView];
	}
 
	[imageView setContentMode:UIViewContentModeScaleAspectFill];
 
	return self;
}
 
@end

Introduction to MapKit on iPhone OS 3.031

Introduction to MapKit on iPhone OS 3.032

iCodeBlogMapViewController.m

-(void)loadOurAnnotations
{
	CLLocationCoordinate2D workingCoordinate;
 
	workingCoordinate.latitude = 40.763856;
	workingCoordinate.longitude = -73.973034;
	iCodeBlogAnnotation *appleStore1 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[appleStore1 setTitle:@"Apple Store 5th Ave."];
	[appleStore1 setSubtitle:@"Apple's Flagship Store"];
	[appleStore1 setAnnotationType:iCodeBlogAnnotationTypeApple];
 
	[mapView addAnnotation:appleStore1];
 
	workingCoordinate.latitude = 51.514298;
	workingCoordinate.longitude = -0.141949;
	iCodeBlogAnnotation *appleStore2 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[appleStore2 setTitle:@"Apple Store St. Regent"];
	[appleStore2 setSubtitle:@"London England"];
	[appleStore2 setAnnotationType:iCodeBlogAnnotationTypeApple];
 
	[mapView addAnnotation:appleStore2];
 
	workingCoordinate.latitude = 35.672284;
	workingCoordinate.longitude = 139.765702;
	iCodeBlogAnnotation *appleStore3 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[appleStore3 setTitle:@"Apple Store Giza"];
	[appleStore3 setSubtitle:@"Tokyo, Japan"];
	[appleStore3 setAnnotationType:iCodeBlogAnnotationTypeApple];
 
	[mapView addAnnotation:appleStore3];
 
	workingCoordinate.latitude = 37.331741;
	workingCoordinate.longitude = -122.030564;
	iCodeBlogAnnotation *appleStore4 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[appleStore4 setTitle:@"Apple Headquarters"];
	[appleStore4 setSubtitle:@"The Mothership"];
	[appleStore4 setAnnotationType:iCodeBlogAnnotationTypeApple];
 
	[mapView addAnnotation:appleStore4];
 
	workingCoordinate.latitude = 41.894518;
	workingCoordinate.longitude = -87.624005;
	iCodeBlogAnnotation *appleStore5 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[appleStore5 setTitle:@"Apple Store Michigan Ave."];
	[appleStore5 setSubtitle:@"Chicago, IL"];
	[appleStore5 setAnnotationType:iCodeBlogAnnotationTypeApple];
 
	[mapView addAnnotation:appleStore5];
 
	workingCoordinate.latitude = 32.264977;
	workingCoordinate.longitude = -110.944011;
	iCodeBlogAnnotation *tacoShop1 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[tacoShop1 setTitle:@"Nico's Taco Shop"];
	[tacoShop1 setSubtitle:@"Tucson, AZ"];
	[tacoShop1 setAnnotationType:iCodeBlogAnnotationTypeTaco];
 
	[mapView addAnnotation:tacoShop1];
 
	workingCoordinate.latitude = 32.743242;
	workingCoordinate.longitude = -117.181451;
	iCodeBlogAnnotation *tacoShop2 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[tacoShop2 setTitle:@"Lucha Libre Gourmet"];
	[tacoShop2 setSubtitle:@"San Diego, CA"];
	[tacoShop2 setAnnotationType:iCodeBlogAnnotationTypeTaco];
 
	[mapView addAnnotation:tacoShop2];
 
	workingCoordinate.latitude = 32.594987;
	workingCoordinate.longitude = -117.060936;
	iCodeBlogAnnotation *tacoShop3 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[tacoShop3 setTitle:@"El Ranchero Taco Shop"];
	[tacoShop3 setSubtitle:@"Rocky Pointe, Mexico"];
	[tacoShop3 setAnnotationType:iCodeBlogAnnotationTypeTaco];
 
	[mapView addAnnotation:tacoShop3];
 
	workingCoordinate.latitude = -34.594859;
	workingCoordinate.longitude = -58.384336;
	iCodeBlogAnnotation *tacoShop4 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[tacoShop4 setTitle:@"Taco Tequila Sangria S.A."];
	[tacoShop4 setSubtitle:@"Buneos Aires, Argentina"];
	[tacoShop4 setAnnotationType:iCodeBlogAnnotationTypeTaco];
 
	[mapView addAnnotation:tacoShop4];
 
	workingCoordinate.latitude = 38.240550;
	workingCoordinate.longitude = -0.526509;
	iCodeBlogAnnotation *tacoShop5 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[tacoShop5 setTitle:@"Albertsma Taco"];
	[tacoShop5 setSubtitle:@"Gran Alacant, Spain"];
	[tacoShop5 setAnnotationType:iCodeBlogAnnotationTypeTaco];
 
	[mapView addAnnotation:tacoShop5];
 
	workingCoordinate.latitude = 33.419490;
	workingCoordinate.longitude = -111.930563;
	iCodeBlogAnnotation *school1 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[school1 setTitle:@"Arizona State University"];
	[school1 setSubtitle:@"Go Sun Devils"];
	[school1 setAnnotationType:iCodeBlogAnnotationTypeEDU];
 
	[mapView addAnnotation:school1];
 
	workingCoordinate.latitude = 35.087537;
	workingCoordinate.longitude = -106.618184;
	iCodeBlogAnnotation *school2 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[school2 setTitle:@"University of New Mexico"];
	[school2 setSubtitle:@"Go Lobos"];
	[school2 setAnnotationType:iCodeBlogAnnotationTypeEDU];
 
	[mapView addAnnotation:school2];
 
	workingCoordinate.latitude = 40.730838;
	workingCoordinate.longitude = -73.997498;
	iCodeBlogAnnotation *school3 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[school3 setTitle:@"New York University"];
	[school3 setSubtitle:@"New York, NY"];
	[school3 setAnnotationType:iCodeBlogAnnotationTypeEDU];
 
	[mapView addAnnotation:school3];
 
	workingCoordinate.latitude = 51.753523;
	workingCoordinate.longitude = -1.253171;
	iCodeBlogAnnotation *school4 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[school4 setTitle:@"Oxford University"];
	[school4 setSubtitle:@"Oxford, England"];
	[school4 setAnnotationType:iCodeBlogAnnotationTypeEDU];
 
	[mapView addAnnotation:school4];
 
	workingCoordinate.latitude = 22.131982;
	workingCoordinate.longitude = 82.142302;
	iCodeBlogAnnotation *school5 = [[iCodeBlogAnnotation alloc] initWithCoordinate:workingCoordinate];
	[school5 setTitle:@"India Institute of Technology"];
	[school5 setSubtitle:@"Delhi, India"];
	[school5 setAnnotationType:iCodeBlogAnnotationTypeEDU];
 
	[mapView addAnnotation:school5];
}

Introduction to MapKit on iPhone OS 3.033

iCodeblogMapViewController.m

- (iCodeBlogAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )annotation
{
	iCodeBlogAnnotationView *annotationView = nil;
 
	// determine the type of annotation, and produce the correct type of annotation view for it.
	iCodeBlogAnnotation* myAnnotation = (iCodeBlogAnnotation *)annotation;
 
	if(myAnnotation.annotationType == iCodeBlogAnnotationTypeApple)
	{
		NSString* identifier = @"Apple";
		iCodeBlogAnnotationView *newAnnotationView = (iCodeBlogAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
 
		if(nil == newAnnotationView)
		{
			newAnnotationView = [[[iCodeBlogAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
		}
 
		annotationView = newAnnotationView;
	}
	else if(myAnnotation.annotationType == iCodeBlogAnnotationTypeEDU)
	{
		NSString* identifier = @"School";
 
		iCodeBlogAnnotationView *newAnnotationView = (iCodeBlogAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
 
		if(nil == newAnnotationView)
		{
			newAnnotationView = [[[iCodeBlogAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
		}
 
		annotationView = newAnnotationView;
	}
	else if(myAnnotation.annotationType == iCodeBlogAnnotationTypeTaco)
	{
		NSString* identifier = @"Taco";
 
		iCodeBlogAnnotationView *newAnnotationView = (iCodeBlogAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
 
		if(nil == newAnnotationView)
		{
			newAnnotationView = [[[iCodeBlogAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier] autorelease];
		}
 
		annotationView = newAnnotationView;
	}
 
	[annotationView setEnabled:YES];
	[annotationView setCanShowCallout:YES];
 
	return annotationView;
}

Introduction to MapKit on iPhone OS 3.034

Introduction to MapKit on iPhone OS 3.035

iCodeBlogMapViewController.m

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 3;
}

Introduction to MapKit on iPhone OS 3.036

iCodeBlogMapViewController.m

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
	if(section == iCodeBlogAnnotationTypeApple)
	{
		return @"Apple Markers";
	}
 
	else if(section == iCodeBlogAnnotationTypeEDU)
	{
		return @"Schools";
	}
 
	else if(section == iCodeBlogAnnotationTypeTaco)
	{
		return @"Taco Shops";
	}
 
	return nil;
}

Introduction to MapKit on iPhone OS 3.037

iCodeBlogMapViewController.m

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
	return 5;
}

Introduction to MapKit on iPhone OS 3.038

Introduction to MapKit on iPhone OS 3.039

iCodeBlogMapViewController.m

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 
	if (cell == nil)
	{
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
 
	NSMutableArray *annotations = [[NSMutableArray alloc] init];
 
	if(indexPath.section == 0)
	{
		for(iCodeBlogAnnotation *annotation in [mapView annotations])
		{
			if([annotation annotationType] == iCodeBlogAnnotationTypeApple)
			{
				[annotations addObject:annotation];
			}
		}
 
		cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];
	}
 
	else if(indexPath.section == 1)
	{
		for(iCodeBlogAnnotation *annotation in [mapView annotations])
		{
			if([annotation annotationType] == iCodeBlogAnnotationTypeEDU)
			{
				[annotations addObject:annotation];
			}
		}
 
		cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];
	}
 
	else if(indexPath.section == 2)
	{
		for(iCodeBlogAnnotation *annotation in [mapView annotations])
		{
			if([annotation annotationType] == iCodeBlogAnnotationTypeTaco)
			{
				[annotations addObject:annotation];
			}
		}
 
		cell.textLabel.text = [[annotations objectAtIndex:indexPath.row] title];
	}
 
    return cell;
}

Introduction to MapKit on iPhone OS 3.040

Introduction to MapKit on iPhone OS 3.041

iCodeBlogMapViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
	for(iCodeBlogAnnotation *annotation in [mapView annotations])
	{
		if([[[[tableView cellForRowAtIndexPath:indexPath] textLabel] text] isEqualToString:[annotation title]])
		{
			[mapView setRegion:MKCoordinateRegionMake([annotation coordinate], MKCoordinateSpanMake(.01, .01)) animated:YES];
		}
	}
}

Code Snippet – Quickly Find The Documents Directory

As many of you may have seen by now, there are quite a few ways to find the documents directory on the iPhone.  For those of you who don’t know, the documents directory of an app is the location where you should save your application data.  While finding the documents directory is a trivial task, it is very important when coding most applications.  Apple has provided quite a few ways for resolving the path to this directory.

If you read through some of Apple’s sample code, you will see their code to do this is generally 3 or 4 lines long.  This seems like a lot of code to perform such a simple task.  Here is a nice one-liner for you to use in your applications.

NSString * docs = [NSHomeDirectory()
						   stringByAppendingPathComponent:@"Documents"];

It’s clean and concise. Happy iCoding!

How to deal with iPhone Device Provisioning without Stabbing Your Eyes Out

Introduction

So for any developer than has joined the iPhone Development program and attempted to throw their app on their phone, the process of provisioning is a familiar and likely painful process. Like many developer you may have several projects going on possibly for several organizations. You can think of provisioning as the paper work your app needs to fill out in order to “board” your phone. The process involves ____ steps:

  1. Get an iPhone Developer Account
  2. Create a certificate request
  3. Download your approved certificate
  4. Register your device
  5. Create an App Id for some app (eg. com.exampleComapny.exampleProduct
  6. Create a provisioning profile that says an app with a certain App ID can run on a device with a certain ID

While there may be a headache or two in the first several steps, Apple does provide a fairly robust overview of how to accomplish those things. We are going to focus on a developer who has gone through these steps and has a provisioning profile available on their machine. Now you may have multiple provisioning profiles on a single machine, but doing that just involves more work. I use this quick trick to modify projects to my provioioning profile so that I can help  test etc.

Instructions

Step 1

Assuming you already have a project created, open up the terminal and navigate into the directory for the project. In my case I have a project called “MyTesterProject”.

Picture 15

Step 2

Now if we do an ls command we can see that there is a .xcodeproj in this directory. We are going to navigate into that. Although in Finder this may look like a file, it is actually a bundle or folder that has things contained in it. Using the change directory command (cd) we can navigate into the project.

Picture 16Picture 17

Step 3

Listing out the directory here we can see that there are several files. The one we are going to focus on is project.pbxproj. This is the file that contains all the configuration settings for this project. What I do here through the terminal is use the command mate to open text mate, however you may use vi or pico or whatever other text editor you like to open the file.

Picture 18Picture 19

Step 4

Now you are going to search for whatever developer this project is currently linked to. For this example lets pretend that this project is configured for a provisioning profile for “Collin Ruffenach” but we want to change it. Search through this document and find the developers name.

Picture 20

Step 5

You will find the name in a section of text that looks similar to this. You need to replace whatever name is there with your name. The other important field begins with “PROVISIONING_ PROFILE”.

Picture 21

The number that you are to replace the provisioning profile number with will be found in xCode. If you go into xCode and into the Window menu, you will see an option for organizer. In organizer you can see all your provisioning profiles. Pick the one you have made for your self and get the Profile Identifier, this is what you will put for the PROVISIONING_PROFILE:

Picture 25Picture 26Picture 27

Step 6

The last thing to do is go into the info.plist file for the project and make sure to change the Bundle Identifier to match the one for the provisioning profile you have. I know at first this seems like a kind of invasive way to do things, but it has really sped up my development and testing time. Hope this tip works for you guys. Thanks for reading and Happy Coding!

Picture 24

Getting Images From The iPhone Photo Library Or Camera Using UIImagePickerController

This will be a simple tutorial showing you how to access the iPhone’s photo library as well as the camera. Since the 3.0 update, the methods for picking photos have been deprecated. So this will be a 3.0 and above tutorial.

We will be creating an applicaiton that will allow you to pick a photo from the library or camera and display it on the screen. Here is a screenshot of what the app will look like:

photo 2

Let’s go ahead and get started…

1. Create A New View Based Application

I called mine photoApp (I will be using this name as reference)

2. Create The IBOutlets and IBAction

Open photoAppViewController.h and add the following code

#import 
 
@interface PhotoAppViewController : UIViewController | UIImagePickerControllerDelegate, UINavigationControllerDelegate | {
	UIImageView * imageView;
	UIButton * choosePhotoBtn;
	UIButton * takePhotoBtn;
}
 
@property (nonatomic, retain) IBOutlet UIImageView * imageView;
@property (nonatomic, retain) IBOutlet UIButton * choosePhotoBtn;
@property (nonatomic, retain) IBOutlet UIButton * takePhotoBtn;
 
-(IBAction) getPhoto:(id) sender;
 
@end

Important: Replace the | in the interface declaration with < and >.  I just used the vertical pipe bc wordpress was replacing it with html encoding.

Notice that we implement the UIImagePickerControlDelegate and the UINavigationControllerDelegate. These are both needed to properly interface with the image picker. The rest of this stuff should be pretty strait forward if you have been reading our tutorials. We set up some outlets to the buttons we are using (this will be to determine which button was pressed). There is also and IBAction that will get called when the user presses either of the buttons. This method (getPhoto) will show the ImagePicker.

3. Create The Interface

Open up photoAppViewController.xib in Interface builder and follow these steps:

  1. Drag a UIImageView on to the main view
  2. Set the Mode of the UIImageView to Aspect Fit in the Attribute inspector
  3. Drag a UIButton on to the view and title it Choose Photo
  4. Drag another UIButton on to the view and title it Take Photo

The interface should look something like this:

screenshot_01

4. Connect The IBoutlets and IBAction

  1. Connect choosePhotoBtn to the UIButton titled Choose Photo
  2. Connect takePhotoBtn to the UIButton titled Take Photo
  3. Connect the imageView to the UIImageView
  4. Connect the Touch Up Inside callback on each of the buttons to the getPhoto method

When you click on File’s Owner the connection inspector should look like this:

screenshot_01

Close Interface Builder

5. Implement The getPhoto Method

Open PhotoAppViewController.m and add the following code:

@synthesize imageView,choosePhotoBtn, takePhotoBtn;
 
-(IBAction) getPhoto:(id) sender {
	UIImagePickerController * picker = [[UIImagePickerController alloc] init];
	picker.delegate = self;
 
	if((UIButton *) sender == choosePhotoBtn) {
		picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
	} else {
		picker.sourceType = UIImagePickerControllerSourceTypeCamera;
	}
 
	[self presentModalViewController:picker animated:YES];
}

Make sure you synthesize your view properties.  Here is what is going on in this method.

We first create a new UIImagePickerController object.  This is a view controller and can be displayed any way you would normally display a view controller (pop on to a navigation view stack, load in a tab view, present as modalviewcontroller).  Next, we set the delegate of the picker to our viewController.  This just means the picker will call a method inside of this class when the user picks a photo.

Next, we determine which button was pressed.  Since both buttons were connected to this method, we can see which one called it by using ==.  Now, here is where Apple has done a great job.  The difference between displaying the camera and photo library comes from setting a single property in the picker.  Looking at the code, it should be pretty obvious which is which.

Finally, we call presentModalViewController with our picker.  This will animate the picker into view from the bottom of the screen to the top.  Depending on the button you press, you should see one of the views below:

photo 3photo

6. Displaying The Selected Image

Once a photo is selected or taken, the ImagePicker will callback to a method in our class called didFinishPickingMediaWithInfo.  Add the following code to your PhotoAppViewController.m file.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
	[picker dismissModalViewControllerAnimated:YES];
	imageView.image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
}

The first line just hides the picker.  The next sets to image property of our image view to an image returned from the picker.  The picker actually returns an NSDictionary.  That is because the other key UIImagePickerControllerMediaType; will return whether this is a video or an image.

And there you have it.  A way to get photos from the iPhone’s image library or camera.  If you have any comments or questions, feel free to write them in the comments section of this post or write them to me on twitter.  You can download the source below. Happy iCoding!

iPhone Tutorial – PhotoApp.zip

WP Like Button Plugin by Free WordPress Templates