Implementing MKMapView Programmatically iOS

Designed by my cousin: Carl Arthell Callanta
Implementing MKMapView Programmatically in iOS has never been this easy. If you google MKMapView iOS Tutorial keywords, you will find tons of results. If you searched on Youtube, you'd get many video tutorials, but I'm quite sure that there are not so many tutorials about this programmatically.

A BIG NOTE: This is not like a Reywenderlich Tutorial, which I find very long and quite boring. That's just my comment. But if you like reading and following tutorials (unlike me), then following the tutorials from that site is totally worth your time.

People usually teach their viewers and subscribers using Xibs/Nibs/Storyboard. One of the many reasons is that doing your project programmatically consumes much more time and effort. But doing your app in that way makes your project better, neater, more organized, and easier to maintain, and more importantly, looks more professional. Well, not using Xibs/Nibs are inevitable in iOS App Development, you will definitely and certainly use Nibs in the future, specifically when building custom cells.

The reason behind why I made this so neat tutorial and step by step instruction is because I want to HELP! I want to help you to understand what you need to understand fast! And second, I will be having a next tutorial related to this, that I barely learned by myself. So without further ado, let's get started.

Make a new project.

Make sure that the Core Data is unchecked, for we will not be using that feature of iOS, and select the Objective-C language.




Prepare your Info.plist 
Add these new keys to your Info.plist, and enter your String values. These keys will be used when the iOS prompts the user to ask for their permission to use their location and map.

NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription

Example string value:
DR'sMKMapViewTut wants to use your Location and Services for Map Viewing.





Delete and Move To Trash the Main.Storyboard
You can find the Main.Storyboard file in your file organizer at the left side of your Xcode. Since we're doing this tutorial programmatically, then there's no reason for that file to stay. If you don't wanna do that, you don't have to follow the next step below for the AppDelegate.

NOTE: Upon deleting the Storyboard file, be sure to erase the value of the Main Interface field in your Project Settings (General Tab). Or else, the app will crash.

Setup your ViewController inside AppDelegate
Since again, this tutorial is programmatically, we need to show our first screen via AppDelegate.

Inside your AppDelegate.m, you will find the first method didFinishLaunchingWithOptions. Put this before the method returns YES. In short, above the return YES.

    // Load the first View Controller.
    ViewController *viewControllerScreen = [[ViewController alloc] init];
    UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:viewControllerScreen];
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window makeKeyAndVisible];
    _window.rootViewController = navCon;
NOTE: Of course, you will need to import your class to AppDelegate before you can use the code above.

Integrate the MKMap to the ViewController
Yes! We're finally here. I hope this post will not be as long as the Reywenderlich's usual tutorial length. Import the following Macros or constants above your #import line in your ViewController.m file. We will use these macros later on as we proceed.

#define     SCREENSIZE        self.view.frame.size
#define     IS_OS_8_OR_LATER  ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
#define     SCREEN_TITLE      @"PrettyITGirl's Cool Map"

Next, import the MapKit and CoreLocation libraries.

#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

We now need to implement or conform to the delegates of CoreLocation and MapKit. We conform to these delegates by adding the code below beside the interface of your View Controller.

<MKMapViewDelegate,CLLocationManagerDelegate>

And just above the @end of your ViewController's Interface, we need to make two properties for MKMapView and for CLLocationManager.
@property (nonatomic, strong) MKMapView *mapView;
@property (nonatomic, strong) CLLocationManager *locationManager;

Are we still good? So your file/code should look like this:



Now, as you just saw in the screenshot above, we need to make a new method, name it whatever you like. And we will put that method inside the viewDidLoad. Why do we need to do this? To make our code clean. As much as possible, don't make your code congested.

We need to implement the method after we call it, in my case I have setupMap. 
- (void)setupMap {
    
    self.title = SCREEN_TITLE;
    
    // Instantiate our location manager property
    self.locationManager = [[CLLocationManager alloc] init];
    _locationManager.delegate = self;
    self.locationManager.distanceFilter = 100.0;
    _locationManager.desiredAccuracy = kCLLocationAccuracyBest;

    // Request Authorization
    if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
        [self.locationManager requestWhenInUseAuthorization];
    }
    
    // Start Updating Location only when user authorized us
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways)
    {
        [_locationManager startUpdatingLocation];
    }

    // We make our initial region, this will be used later
    CLLocationCoordinate2D noLocation;
    MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(noLocation, 500, 500);

    // Instantiate our MapView - YIS!
    self.mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0, 0, SCREENSIZE.width, SCREENSIZE.height)];
    _mapView.showsUserLocation = YES;
    _mapView.delegate = self;
    
    // Set the initial zoom and size of the map that we can see in our screen
    MKCoordinateRegion adjustedRegion = [_mapView regionThatFits:viewRegion];
    if(adjustedRegion.center.longitude == -180.00000000){
        NSLog(@"Invalid region!");
    } else {
        [_mapView setRegion:adjustedRegion animated:YES];
    }
    
    // If you want to show the user's location, then set it to YES
    _mapView.showsUserLocation = YES;
    
    // Finally, we add our mapview as a subview of our main View
    [self.view addSubview:_mapView];
}


I have already explained the code above by putting necessary comments. Try to keep up! If you wanna ask something, just go ahead and contact me or post a comment.

Implement the Delegates of CoreLocation and MapKit.

// The warnings of our app for the users:
- (void)locationManager:(CLLocationManager*)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    switch (status) {
        case kCLAuthorizationStatusNotDetermined: {
            NSLog(@"User still thinking granting location access!");
        } break;
        case kCLAuthorizationStatusDenied: {
            [self showAlertWithTitle:NSLocalizedString(@"Location Services is off!", nil)
                      andWithMessage:NSLocalizedString(@"Location services are currently disabled. \nTo enable, go to Settings>App_Name>Location>\nWhile Using the App.", nil)];
        } break;
        case kCLAuthorizationStatusAuthorizedWhenInUse:
        case kCLAuthorizationStatusAuthorizedAlways: {
            NSLog(@"user permits location, do nothing...");
            [self.locationManager startUpdatingLocation];
        } break;
        default:
            break;
    }
}

-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
    [self showAlertWithTitle:NSLocalizedString(@"No Internet Connection!", nil)
              andWithMessage:NSLocalizedString(@"Sorry! Please check your internet connection.", nil)];
}


Oh, I'm hating myself right now! I feel like this tutorial is getting as long as Reywenderlich's. Ughh! Anyway, this will be the last part: Implement the alert method I made.

// Now, this is the method I made to support both iOS7 and below and iOS8 and above
#pragma mark - ALERT CONTROLLER
- (void)showAlertWithTitle:(NSString *)alertTitle andWithMessage:(NSString *)alertMessage {
    if (IS_OS_8_OR_LATER) {
        UIAlertController *alertController = [UIAlertController
                                              alertControllerWithTitle:alertTitle
                                              message:alertMessage
                                              preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction *okAction = [UIAlertAction
                                   actionWithTitle:NSLocalizedString(@"OK", nil)
                                   style:UIAlertActionStyleCancel
                                   handler:^(UIAlertAction *action)
                                   {
                                       
                                   }];
        
        [alertController addAction:okAction];
        
        [self presentViewController:alertController animated:YES completion:nil];
    } else {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle
                                                            message:alertMessage
                                                           delegate:nil
                                                  cancelButtonTitle:NSLocalizedString(@"OK", nil)
                                                  otherButtonTitles:nil, nil];
        [alertView show];
    }
}


YES! YOU JUST FINISHED FOLLOWING MY VERY FIRST LONG YET COOL TUTORIAL I MADE!!! CONGRATULATIONS! If you enjoyed this easy tutorial, subscribe and share!

Also, wait for my next tutorial: Adding Custom Annotation With Data!

FIN.

Post a Comment