Archive

Posts Tagged ‘iphone’

iPhone Note #16: Creating a MKMapView using IB

October 29th, 2009 rupert 4 comments

In this tutorial we will be addking MKMapView using IB to a ViewController.

1. XCode -> File -> New Project -> View-based Application.

Name the project “SimpleMapIB”

2. Make sure everything works out accordingly before doing anything. Let’s test from the iPhone Simulator. Click on “Build and Go”. You should see the iPhone Simulator running with a gray background. Bring up the Debugger Console (XCode -> Run -> Console) as well and it should be free from errors.

3. Now double-click on “SimpleMapIBViewController.xib”, it should open in Interface Builder.

4. Drag a UIToolbar to the bottom. We will use the button as a GPS in our next tutorial.

5. Drag MKMapView to the middle of the screen.

6. IB -> save

7. Now we need to reference Mapkit. Go to XCode -> Project -> Edit Active Target “SimpleMapIB”. Click the + icon on the bottom left, choose MapKit.framework, then “Add”.

SimpleMapIB-1.png

You should see Mapkit added to the frameworks.

SimpleMapIB-2.png

You could also organize XCode’s left panel by dragging “MapKit.framework” to the Frameworks Group.

SimpleMapIB-3.png

7. Let’s code SimpleMapIBViewController.h

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
 
@interface SimpleMapIBViewController : UIViewController {
	IBOutlet MKMapView *mapview;
}
 
@property(nonatomic, retain) IBOutlet MKMapView *mapview;
 
@end

8. Now back to IB. Click on the “File’s Owner” and you should see your outlets displayed “Connections Inspector”. Drag “mapview” to MKMapView Control.


SimpleMapIB-4-sm.png

Note: You can click for a bigger image.

9. Now to set “SimpleMapIBViewController” as the delegate. Click on the MKMapView, it should be highlighted and in the “Connections Inspector” notice the “delegate” come out in the Outlets. Drag it to the “Files Owner” to set “SimpleMapIBViewController” as the delegate.

SimpleMapIB-5-sm.png
Note: You can click for a bigger image.

10. Now, let’s test. Hit “Clean All” then “Build and Go”. You should see something like this..

SimpleMapIB-6.png

11. Now to test that the delegate is setup accordingly, we can code on the viewDidLoad.

- (void)viewDidLoad {
    mapview.mapType = MKMapTypeSatellite;
 
	[super viewDidLoad];
}

12, Now press command-Y for “Build and Debug”. We should see a satellite map instead.
SimpleMapIB-7.png

13. That seems a little bit dull, lets add a segmented control so we can switch between maptypes (standard, satellite, hybrid). In IB, drag a UISegmentedControl in the UIToolbar at the bottom. Add another segment, making a total of three. Then change the titles to “Normal”, “Sat”, “Hybrid” respectively.

SimpleMapIB-8.png.

14. Let’s code. In the interface, we need to add a method that would be called by the segmentedControl whened the values changed.

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
 
@interface SimpleMapIBViewController : UIViewController {
	IBOutlet MKMapView *mapview;
	IBOutlet UISegmentedControl *segmentedControlMapType;
}
 
@property(nonatomic, retain) IBOutlet MKMapView *mapview;
@property(nonatomic, retain) IBOutlet UISegmentedControl *segmentedControlMapType;
 
- (IBAction)changeMapType: (id)sender;
 
@end

Now in IB, click on the “File’s Owner” and you should see your outlets displayed “Connections Inspector”. Drag “segmentedControlMapType” to the segmented control just like what we did for mapview.

15. In the implementation, we can switch between the segmentIndex and display the corresponding MKMapType.

- (IBAction)changeMapType: (id)sender{
	if(segmentedControlMapType.selectedSegmentIndex == 0){
		mapview.mapType = MKMapTypeStandard;
	}
	else if(segmentedControlMapType.selectedSegmentIndex == 1){
		mapview.mapType = MKMapTypeSatellite;
	}
	else if(segmentedControlMapType.selectedSegmentIndex == 2){
		mapview.mapType = MKMapTypeHybrid;
	}
 
}

16. Now to hook the IBAction of the UISegmentedControl to the method. In IB, click on the segmented control and in the “Connections Inspector”, drag the “Value Changed” Event to the “File’s Owner” and choose “changeMapType”.

“>SimpleMapIB-9-sm.png

17. Now test in the simulator again and the hybrid button should work.
SimpleMapIB-10.png

Download SimpleMapIB.zip

In my next tutorial, I would be hooking up a GPS button which handles location updates using CoreLocation.

Categories: iphone Tags:

iPhone Note #15: Omnigraffle iPhone Stencils, Screen Mockups via PPT, creating an iPhone interface before actual development

October 20th, 2009 rupert Comments off

stencil.gif

I can not argue enough how valuable an iphone stencil will be in seeing the overall design/flow of an application. I should have done this a long time ago.

Well, I am also one of those eager developers who dives right into coding and see how it goes. But after having the fundamentals of iphone development, objective-c, and app-store submission, I’m taking on a different approach by creating screen mockups mainly for the following reasons:

1. Reach out quickly to the client.

2. Provides a bird’s eye view of the whole application. Provides alternative screens for a better user experience..

3. A follow up on the screen mockups is a powerpoint with actual links to other slides thus mimicing an iphone interface. Note, it is not a complete replica of the simulator but just enough for decision makers to understand what’s in there.

stencil-ppt.jpg

In powerpoint, you can just quickly overlay a transparent polygon on top of the UIButton then attach a hyperlink to another slide.

Hope this post helps you even if it’s not related to coding. On my next post, which is currently buried in my drafts–hopefully it will not be that long, I learned about integrating with Mobile Advertising Networks.

Categories: iphone Tags:

iPhone Note #13: Drawing Point, Line, Polygon on top of MKMapview

September 11th, 2009 rupert Comments off

Now I have a reason to study Quartz2D! I am trying to draw a point, line and polygon on top of MKMapview. I will list below important links for reference:

1. Always use Apple’s iPhone OS Reference Library Documentation.. Under “Topics” > “Graphics & Animation” you will find a lot of references, guides and sample code.

2. Start out with the Getting Started with Graphics and Animation. Note, if you ever read the line below and try to find Finger Sketch, please drop me a comment. I could not find it anywhere!

“Next, examine the Finger Sketch sample code in Xcode.”

3. iPhone Application Programming Guide: Graphics and Drawing.

4. Note: I haven’t read everything on Quartz 2D Programming Guide, but I went straight to the Paths Section.

5. Lets look at some sample codes, especially the QuartzDemo.

6. Now, I presume you know IB, add a MKMapView and a UIToolbar at the bottom. Add four UIBarButtonItems for: Map, Point, Line, Polygon. Set MKMapView’s delegate to the File’s Owner. Hook up the UIBarButtonItem IBOutlets to your buttons, so we can change the appearance of the buttons when pressed. Lastly, hook up our IBAction methods for each button.

The Map button allows to pan/zoom on the Map. If any of the three geometry buttons (PT, LN, PG) is pressed, we unhide the GeometryView(which is a UIView) to allow touchEvents to proceed.

TO DO: Watch out for this segment as I will update it with code later.

7. Now to draw a line, we implement the code below in our GeometryView.drawRect method. As we loop through each Pin, we add a line to the point. Afterwards, we stroke the path, thus drawing the lines.

CGContextRef context = UIGraphicsGetCurrentContext();
 
// Drawing lines with a white stroke color
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
 
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(context, 2.0);
 
if( [pinFactory actualPinCount] > 1){
 
	Pin *pin1 = (Pin *)[[pinFactory pinArray] objectAtIndex:0];
	CGPoint pt1 = pin1.touchLocation;
	CGContextMoveToPoint(context, pt1.x, pt1.y);
 
	for (int i = 1; i < ([pinFactory actualPinCount]); i++)
	{
		Pin *pin2 = (Pin *)[[pinFactory pinArray] objectAtIndex:i];
		CGPoint pt2 = pin2.touchLocation;
		CGContextAddLineToPoint(context, pt2.x, pt2.y);
	}
 
	CGContextStrokePath(context);
}

line.png

8. To draw a polygon, we close the path of lines then fill the polygon.

CGContextClosePath(context);
 
CGContextDrawPath(context, kCGPathFillStroke);

poly.png

Note: I’ll try to post the sample code when I have time. I’m trying to minimize blogging to 10 mins per post as my work tasks/personal development tasks is piling up…

Categories: iphone Tags:

iPhone Note #12: Adding a UIButton on a UITableViewCell (Borderless)

September 9th, 2009 rupert Comments off

1. Im trying to add two UIbuttons to a UITableViewCell, similar to the contacts app. Creating the UIButtons programmatically and adding them to the cell’s subview is trivial. However the interface is a bit different from the contacts app, see image here…

UIButtons-dirty.png

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ButtonCell"] autorelease];
 
UIButton *buttonLeft = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonLeft setTitle:@"Left" forState:UIControlStateNormal];
[buttonLeft setFrame: CGRectMake( 10.0f, 3.0f, 145.0f, 40.0f)];
[buttonLeft addTarget:self action:@selector(addToFavorites) forControlEvents:UIControlEventTouchUpInside];
 
UIButton *buttonRight = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonRight setTitle:@"Right" forState:UIControlStateNormal];
[buttonRight setFrame: CGRectMake( 165.0f, 3.0f, 145.0f, 40.0f)];
[buttonRight addTarget:self action:@selector(addToFavorites) forControlEvents:UIControlEventTouchUpInside];
 
[cell addSubview:buttonLeft];
[cell addSubview:buttonRight];

2. So to make the background the same as UITableViewStyleGrouped, we can implement:

cell.backgroundColor = [UIColor groupTableViewBackgroundColor];

But I could still see the border of the UITableViewCell.. see image below…
UIButtons-not-so-clean.png

3. The crux of it was to implement a UIView, set the background as UITableViewStyleGrouped and add that as a cell’s backgroundView.

cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"ButtonCell"] autorelease];
 
UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 44.0f)];
backgroundView.backgroundColor = [UIColor groupTableViewBackgroundColor];
 
cell.backgroundView = backgroundView;
 
UIButton *buttonLeft = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonLeft setTitle:@"Left" forState:UIControlStateNormal];
[buttonLeft setFrame: CGRectMake( 10.0f, 3.0f, 145.0f, 40.0f)];
[buttonLeft addTarget:self action:@selector(addToFavorites) forControlEvents:UIControlEventTouchUpInside];
 
UIButton *buttonRight = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[buttonRight setTitle:@"Right" forState:UIControlStateNormal];
[buttonRight setFrame: CGRectMake( 165.0f, 3.0f, 145.0f, 40.0f)];
[buttonRight addTarget:self action:@selector(addToFavorites) forControlEvents:UIControlEventTouchUpInside];
 
[cell addSubview:buttonLeft];
[cell addSubview:buttonRight];
 
[backgroundView release];

Now the interface is a whole lot cleaner and the resulting image is better…

UIButtons-clean.png

Categories: iphone Tags:

iPhone Note #11: Unit Testing

September 7th, 2009 rupert Comments off

Test first, develop later! That’s the greeting when you visit OCUnit, similar to JUnit. Note that for this tutorial, you do not need to install OCUnit as it comes “built-in” in XCode as of v2.1.

1. Create a new iPhone Window-based application project “SampleTest”.

2. Our subject for testing is Converter.m which converts kilometers to meters. Let’s implement an incorrect conversion by specifying 1km = 100 meters (should be 1000 meters) so we can see that the unit test captures it below…

#import "Converter.h"
 
@implementation Converter
 
- (id)init{
	if(self = [super init]){
 
	}
	return self;
}
 
- (int)convertKilometersToMeters:(int)km{
	return km * 100;
}
 
@end

3. Add another target “UnitTests”. Right click on Targets -> Add -> New Target… -> Choose Unit Test Bundle.

unit-test-bundle.png

4. Name it “UnitTests”. After hitting submit, you will be presented with the project settings for “UnitTests”.

unit-test-name2.png

5. Go to the General Tab -> Click on the “+” icon above “Linked Libraries”. Choose “SampleTest” as the application we have direct dependency with.

unit-test-dependency-3.png

6. Close the Settings. To check, navigate under “Groups & Files” -> Targets. You should see the SampleTest Application Icon just below “UnitTests”.

unit-test-tree-4.png

7. Right Click on “Sample Test” -> Add -> New File…

unit-test-class5.png

8. Name the file “ConverterTest. Don’t forget to also create the header file (default). Specify it also in a different directory under “Location”. Then check the UnitTests as the “Targets”. When you hit “Finish” it will ask you to create the folder “Tests”

unit-test-class6.png

Tip: Keep things organize and put it under a “Tests” Group. Right Click on “Sample Test” -> Add -> New Group… Name it “Tests”, then drag the files (ConverterTest.h and ConverterTest.m) into that group.

9. Open up ConverterTest.h and notice that “SenTestingKit.h” is already imported. Now let’s add method testKilometersToMeters as shown below. Test methods usually start out with a test prefix.

In the implementation, let’s import Converter.h and use STAssertTrue. To test the convertKilometersToMeters method, we are asserting that the result should be 1000. If not, then we should know! That is why we are writing a unit test for.. making sure that our implementation doesn’t break.

#import "ConverterTest.h"
#import "Converter.h"
 
@implementation ConverterTest
 
- (void)testKilometersToMeters{
	int km = 1;
	Converter *converter = [[Converter alloc] init];
	int meters = [converter convertKilometersToMeters:km];
	STAssertTrue(meters == 1000, @"converting %d km to meters should equal 1000, instead received %d", km, meters);
}
 
@end

12. Now, before we build our target “UnitTests”, we need to include additional class references from our application. Drag Converter.m to the “Compile Sources” under UnitTests.

unit-test-drag7.png

13. Now we can build. There are many ways to do this. My preference is to do a clean build when testing. Right Click on Sample Test then choose “Clean SampleTest”. Afterwards choose “Build SampleTest”.

unit-test-build8.png

If you have a succesful build for SampleTest, lets do the same for our “UnitTests”.

unit-test-build9.png

13. Here’s the crux of it. Notice the error in your “Build Results”?

/Users/rupert/projects/iphone/SampleTest/Tests/ConverterTest.m:18: error: -[ConverterTest testKilometersToMeters] : "meters == 1000" should be true. converting 1 km to meters should equal 1000, instead received 100

unit-test-results.png

Now changing the correct implementation of convertKilometersToMeters will put the error away and you will have a successful build.

- (int)convertKilometersToMeters:(int)km{
	return km * 1000;
}

14. Look up the assert methods from SenTest.h.

#import <Foundation/NSObject.h>
#import "SenTest.h"
 
#define STAssertNil(a1, description, ...)
#define STAssertNotNil(a1, description, ...)
#define STAssertTrue(expression, description, ...)
#define STAssertFalse(expression, description, ...)
#define STAssertEqualObjects(a1, a2, description, ...)
#define STAssertEquals(a1, a2, description, ...)
#define STAssertEqualsWithAccuracy(left, right, accuracy, description, ...)
#define STAssertFalseNoThrow(expression, description, ...)
....

References:

http://developer.apple.com/mac/library/documentation/DeveloperTools/Conceptual/UnitTesting/Articles/CreatingTests.html

http://developer.apple.com/tools/unittest.html

Download: SampleTest.zip

Categories: iphone Tags: