Challenge: Changing the Map Type


#1

*Warning - Possible spoiler alert*

Hi,

I was finished reading through Chapter 5 and got to the "Changing the Map Type and found out it was a tricky one… I searched for a while before figuring out that UISegmentedControl does not (appear to) offer a delegate class like MKReverseGeocoderDelegate from the previous challenge. I kept searching so hard because I thought that I would find a delegate class for UISegmentedControl since the book does not teach about anything else… up to this point.

I had to resort using an “IBAction” method in WhereamiAppDelegate.h and connect the event “Value Changed” of my UISegmentedControl in Interface Builder to the WhereamiAppDelegate class.

So, here is my “IBAction” method in the implementation file WhereamiAppDelegate.m (“typeSwitcher” is an “IBOutlet” connected to the UISegmentedControl in Interface Builder):

- (IBAction)segmentedControlAction:(id)sender {
	int index = [typeSwitcher selectedSegmentIndex];
	switch (index) {
		case 0:
			[mapView setMapType:MKMapTypeStandard];
			break;
		case 1:
			[mapView setMapType:MKMapTypeSatellite];
			break;
		case 2:
			[mapView setMapType:MKMapTypeHybrid];
			break;
	}
}

It was pretty simple after all, using the “IBAction” technique, but I am still wondering if there was any other way I could have completed this challenge?

Thanks in advance.


#2

I did the same thing as you, except I used if statements instead of a switch. :slight_smile:

Incidentally, when this method is called, sender is actually the segmented controller when called, so we could have gotten by with the action method and not hooking up the outlet.


#3

I initially tried to set up some form of static array of the three strings that are used to set the mapType field in mapView, however I couldn’t figure that part out (it seems like it should be easy…) but when I finally did manage to build an NSMutableArray, I found that it either wouldn’t pass to the IBAction method (was a local variable) or wouldn’t build correctly (in the case where it was declared in the .h file as an instance variable.)

The initial plan was to set up this:

[mapView setMapType:[mapTypesArray objectAtIndex:[mapTypeController.selectedSegmentIndex]-1]]];

as the IBAction method code. It simply looks at a table of values, picks the one corresponding to the user’s selection, and sets the mapType accordingly.

My thought process was that conditional functions take more processor time than simply a lookup table.

Joe - any thoughts?


#4

Hi,

In MKTypes.h you can see the definition for MKMapType:

enum {
MKMapTypeStandard = 0,
MKMapTypeSatellite,
MKMapTypeHybrid
};
typedef NSUInteger MKMapType;

So the argument for setMapType is a NSUInteger (rather than a string)

which means that you could do the following in your segmentedControl valueChanged method (providing your segment labels are in the same order)

- (IBAction)segmentedControlAction:(id)sender {
{
	[mapView setMapType:[sender selectedSegmentIndex]];
}

but it’s a tiny efficiency over the easier to read and maintain switch statement version.

Gareth


#5

joecouture, did you implement this method?
[segmentedControl addTarget:self
action:@selector(segmentedControlAction:)
forControlEvents:UIControlEventValueChanged];

I tried your method, however I still cannot get it to work.


#6

I think you can make the connection in Interface Builder and have it call the addTarget:action:forControlEvents: method for you to connect the ValueChanged action of the segmented control to the segmentedControlAction: method. In Interface Builder you should be able to control-click on the segmented control and then drag a link from the ValueChanged menu item to the app delegate. In the pop-up menu which appears on the destination delegate object, select the segmentedControlAction: method which was declared to have an IBAction return type in the delegate’s header file.

Hope this helps but I might have misunderstood your question, in which case it will probably not be of much assistance.


#7

I have a question about alloc and init in this example…

in WhereamiAppDelegate.h,

i have an instance variable of
IBOutlet UISegmentedControl *mapViewChooser;

Should i not have to then allocate memory and initialise this in WhereamiAppDelegate.m with
mapViewChooser = [[UISegmentedControl alloc] init];

What are the rules of when you need to alloc and init and when you don’t?


#8

I think you would only have to init/alloc the segmented control if you build it from scratch. If it’s dragged into the .xib file, then that takes care of all the housekeeping chores during runtime.


#9

hi there everybody

I’m in trouble with this challenge… in IB I can’t create the connection between the UISegmentedControl and the AppDelegate because I can’t find the Outlets in the connections panel

If I control+click the AppDelegate in the connections panel in the outlets list I can’t see the IBOutlet I created for the UISegmentedControl
I don’t understand what I did wrong…

PS sorry for my english


#10

I answer my self…

I’ve figured it out. I followed my steps once again and finally I did it