본문 바로가기
아이폰 개발/ios 개념&튜토리얼

Firebase를 이용해서 좌표 저장 후 지도에 표시

by 인생여희 2020. 7. 29.

#.완성된 모습

좌측 상단에 start 버튼을 누르면 firebase에 현재 좌표를 찍는다. 이동하면서도 좌표가 firebase에 저장되고, 저장된 좌표를 이용해서 지도 위에 경로를 표시해준다.

 

*먼저 지도표시와 위도, 경도 라이브러리를 위한 MapKit.framework 와 CoreLocation.framework를 추가한다.

*info.plist 에서 위치 수집을 위한 설정을 해준다.

*구글 firebase API를 사용하기위한 설치를 진행한다. (참고)

 

 


 

AppDelegate.h

#import <UIKit/UIKit.h>
@import Firebase;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
view raw AppDelegate.h hosted with ❤ by GitHub

 

AppDelegate.m

#import "AppDelegate.h"
#import "ViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//파이어 베이스 사용 설정
[FIRApp configure];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(@"백그라운드 모드 진입 - ");
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(@"포그라운드 모드 진입 - ");
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end
view raw AppDelegate.m hosted with ❤ by GitHub

 

ViewController.h

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
@import Firebase;
@interface ViewController : UIViewController<CLLocationManagerDelegate , MKMapViewDelegate>
@property (nonatomic, retain) CLLocationManager *locationManager; //로케이션 메니저
@property (weak, nonatomic) IBOutlet MKMapView *mk; //지도
@property (nonatomic, retain) MKPolyline *routeLine; //라인
@property (nonatomic, retain) MKPolylineView *routeLineView; //라인뷰
@property (strong, nonatomic) FIRDatabaseReference *ref; //파이어 베이스
@property (strong, nonatomic) IBOutlet UIBarButtonItem *startButton; //위치수집 시작
@property (strong, nonatomic) IBOutlet UIBarButtonItem *resetButton; //저장된 위치 삭제
@end

 

ViewController.m

#import "ViewController.h"
@implementation ViewController;
@synthesize locationManager ,mk ,routeLine , routeLineView , startButton, resetButton;
- (void)viewDidLoad {
[super viewDidLoad];
//1.mapkitView 셋팅 : 지도에서 유저의 현재 위치 보이기,지도 설정
mk.showsUserLocation = YES;
mk.mapType = MKMapTypeStandard;
mk.delegate = self;
//firebase db 초기화
self.ref = [[FIRDatabase database] reference];
//2.LocationManager 생성 + 초기화
if (locationManager == nil) {
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyBest; //지도 정확도 최상
locationManager.delegate = self; // Location Receiver 콜백에 대한 delegate 설정
locationManager.distanceFilter = 100; //100 meters 기준 위치 업데이트
locationManager.pausesLocationUpdatesAutomatically = NO; //자동으로 멈춤 방지
//지도 기본 zoom 설정
CLLocationCoordinate2D loc = locationManager.location.coordinate;
if (CLLocationCoordinate2DIsValid(loc)) {
NSLog(@"Coordinate valid");
MKCoordinateRegion userLoc = MKCoordinateRegionMakeWithDistance(loc, 400, 400);
[mk setRegion:userLoc];
} else {
NSLog(@"Coordinate invalid");
}
}
//소스에서 CLLocationManager 초기화 후 앱사용시에만 위치정보 수집을 하겠다
if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
NSLog(@"requestAlwaysAuthorization - ");
[locationManager requestAlwaysAuthorization];
}
//백그라운드 상태에서도 위치정보 갱신을 하겠다는 코드 호출
if ([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {
NSLog(@"setAllowsBackgroundLocationUpdates - ");
[locationManager setAllowsBackgroundLocationUpdates:YES];
}
//Location Manager 시작하기
//[locationManager startMonitoringSignificantLocationChanges];
[locationManager startUpdatingLocation];
//파이어 베이스 데이터 읽기
[_ref observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
//db에 존재하는 경로 개수
int cnt = (int)snapshot.childrenCount;
CLLocationCoordinate2D coordinateArray[cnt];
int ii = 0;
//지도에 선 그리기릴 위한 CLLocationCoordinate2DMake 만들기
for ( FIRDataSnapshot *child in snapshot.children) {
//위도 , 경도
NSString *latString = [child.value valueForKey:@"lat"];
NSString *longString = [child.value valueForKey:@"long"];
double latDouble = [latString doubleValue];
double longDouble = [longString doubleValue];
coordinateArray[ii] = CLLocationCoordinate2DMake(latDouble, longDouble);
ii++;
}
//지도에 선 그리기
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coordinateArray count:cnt];
[self.mk addOverlay:polyline];
self.routeLine = polyline;
//선 설정
[self drawPoliyLine];
} withCancelBlock:^(NSError * _Nonnull error) {
NSLog(@"%@", error.localizedDescription);
}];
}
//일정 거리 이상 이동했을때 호출되는 메소드
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(@"locationManager didUpdateLocations");
NSLog(@"Latitude : %f", manager.location.coordinate.latitude);
NSLog(@"Longitude : %f", manager.location.coordinate.longitude);
//출발 버튼 눌렀을때 - 출발 중일때만 좌표 수집
if([startButton.title isEqualToString:@"STOP"]){
//위도 , 경도
NSString* latS = [NSString stringWithFormat:@"%f", manager.location.coordinate.latitude];
NSString* longS = [NSString stringWithFormat:@"%f", manager.location.coordinate.longitude];
//좌표를 위한 key 값 : 현재시분초
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
NSLog(@"%@",[dateFormatter stringFromDate:[NSDate date]]);
NSString *datenow = [dateFormatter stringFromDate:[NSDate date]];
//db 저장을 위한 객체
NSDictionary*location = @{
@"id":datenow,
@"lat":latS,
@"long":longS
};
//현재 좌표 파이어 베이스에 저장
[[self.ref child:datenow] setValue:location];
}
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay{
if(overlay == self.routeLine)
{
if(nil == self.routeLineView)
{
[self drawPoliyLine];
}
return self.routeLineView;
}
return nil;
}
//선그리기 - 초기화 및 셋팅
-(void) drawPoliyLine {
// create an MKPolylineView and add it to the map view
self.routeLineView = [[MKPolylineView alloc]initWithPolyline:self.routeLine];
self.routeLineView.strokeColor = [UIColor redColor];
self.routeLineView.lineWidth = 3;
}
//location 오류
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(@"Cannot find location");
}
//출발 - 정지 토글 버튼
- (IBAction)startButtonAction:(id)sender {
NSLog(@"startButtonAction");
if([startButton.title isEqualToString:@"START"]){
[startButton setTitle:@"STOP"];
}else if([startButton.title isEqualToString:@"STOP"]){
[startButton setTitle:@"START"];
}
}
//파이어 베이스 db 데이터 전체 삭제
- (IBAction)resetButtonAction:(id)sender {
NSLog(@"resetButtonAction");
[_ref removeValue];
}
@end

 

Main.Storyboard

 

예제파일

WhereDoILive.zip
0.02MB

 

 


 

전체거리 계산 예제

//*두 좌표 거리 계산
//1.시작 지점
Pin *firstPin = [self.allPins objectAtIndex:0];
CLLocationCoordinate2D firstCoordinate = firstPin.coordinate;
CLLocation *firstLocation = [[CLLocation alloc] initWithLatitude:firstCoordinate.latitude longitude:firstCoordinate.longitude];
//2.끝 지점
Pin *secondPin = [self.allPins objectAtIndex:1];
CLLocationCoordinate2D secondCoordinate = secondPin.coordinate;
CLLocation *secondLocation = [[CLLocation alloc] initWithLatitude:secondCoordinate.latitude longitude:secondCoordinate.longitude];
//3.double 타입 - 출력
CLLocationDistance distance = [secondLocation distanceFromLocation:firstLocation];
NSString *distanceS = [NSString stringWithFormat: @"%.2f 미터", distance];
NSLog(@"거리 : %@" , distanceS);
/*****************************************/
//*전체 거리 계산
if (self.allPins.count < 2) {
NSLog(@"계산할 지점이 없습니다.");
}else {
CLLocation *newLoc; //첫 지점
CLLocation *oldLoc; //다음 지점
CLLocationDistance distance = 0.0; //전체 거리
for (int i = 0; i < (self.allPins.count -1); i++) {
//첫지점
Pin *firstPin = [self.allPins objectAtIndex:i];
CLLocationCoordinate2D firstCoordinate = firstPin.coordinate;
newLoc = [[CLLocation alloc] initWithLatitude:firstCoordinate.latitude longitude:firstCoordinate.longitude];
//두번째지점
Pin *secondPin = [self.allPins objectAtIndex:i+1];
CLLocationCoordinate2D secondCoordinate = secondPin.coordinate;
oldLoc = [[CLLocation alloc] initWithLatitude:secondCoordinate.latitude longitude:secondCoordinate.longitude];
//3.전체거리에 +
distance += [oldLoc distanceFromLocation:newLoc];
}
//4.출력
NSString *distanceS = [NSString stringWithFormat: @"%.2f 미터", distance];
NSLog(@"전체거리 : %@" , distanceS);
}
view raw distance.m hosted with ❤ by GitHub

 

WhereDoILive.zip
0.02MB

 

 

참고 1. : 폴리라인

참고 2. : iOS :지도에 매력적인 경로 그리기