반응형

튜토리얼 원문 Login and Signup Views

단말단 개발자들이 서버단 구현에 쏟을 시간을 절약을 하게 만들어 주는 서비스입니다. 국내에는 비슷한 서비스로 KTH의 baas.io 가 있습니다.


iOS 로그인과 가입 뷰 컨트롤러를 설정 방법을 배우도록 하자. 사용자 정의 및 PFUser를 사용하여 여러분의 앱에 삽입 할 수 있게 내장된 뷰 셋을 제공한다. 

이 튜토리얼의 소스 다운로드 링크: .zip | GitHub

로그인과 가입 흐름을 만드는 것은 복잡한 과정이다. 아직까지 개발자들은 모든 앱에 이런 코드들을 재 작성하고 있다. 이런 프로세스를 좀 더 쉽게 도와주기 위해, 우리는 단지 몇 줄의 코드로 다양한 로그인과 가입 옵션을 추가 할 수 있는 PFLogInViewController  FSignUpViewController를 만들었다. 

이 튜토리얼에서는 우리는 두 개의 뷰 컨트롤러의 모든것을 탐험 할 것이다. 1장에서는 델리게이터를 로그인과 가입과 연동하는 것을 배울 것이다. 2장에서는 페이스북과 트위터 로그인 흐름을 생성하여 로그인 옵션을 사용자 정의 하는 방법을 배울 것이다. 마지막 3장에서는 PFLogInViewController  PFSignUpViewController의 서브 클래스를 생성하여 뷰의 사용자 정의를 알아 볼 것이다. 

튜토리얼을 시작하기 전에, 위의 링크에서 소스 코드를 다운로드 하고 함께 따라해 주길 바란다.  

Default PFLoginViewController

1. 기본적인 로그인과 가입 흐름

튜토리얼의 첫 장에서는 DefaultSettingsViewController를 다룰 것이다. 로그인과 가입 뷰 컨트롤러가 제공하는 기본적인 설정을 사용하여 표준 로그인 흐름을 구현 하였다.

1.1. 로그인 뷰 컨트롤러

예제 앱에서는, viewDidAppear 메소드에서 유저가 로그인 하지 않았을 때  PFLogInViewController가 나타는 것으로 시작한다. 여러분의 앱에서는 앱 델리케이트 또는 루트 뷰 컨트롤러에 다음 코드를 작성 해야 할 것이다.

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
     
    if (![PFUser currentUser]) { // 유저가 로그인 하지 않았을 경우
        // 로그인 뷰 컨트롤러를 생성한다
        PFLogInViewController *logInViewController = [[PFLogInViewController alloc] init];
        [logInViewController setDelegate:self]; // 자신을 델리게이트로 설정한다
         
        // 가입 뷰 트롤러를 생성한다
        PFSignUpViewController *signUpViewController = [[PFSignUpViewController alloc] init];
        [signUpViewController setDelegate:self]; // 자신을 델리게이트로 설정한다
         
        // 로그인 뷰 컨트롤러에 가입 컨트롤러를 할당한다
        [logInViewController setSignUpController:signUpViewController];
         
        // 로그인 뷰 컨트롤러를 보여준다
        [self presentViewController:logInViewController animated:YES completion:NULL];
    }
}

현재 컨트롤러(DefaultSettingsViewController)를 두 개의 로그인과 가입 뷰 컨트롤러에 델리게이트로 설정하는 것을 확인 하였을 것이다. 델리게이트 메소드는 컨트롤러와 상호작용 및 이벤트 정보를 얻는데 사용될 것이다. 이 장의 마지막에서는 가능한 프로토콜 메소드 그리고 어떻게 앱에서 사용 할 수 있는 지를 살펴 볼 것이다.

1.2. PFLogInViewControllerDelegate

이 메소드를 구현하기 위해 헤더 파일에 프로토콜을 추가 한다.

// 두 개의 델리게이트를 구현
@interface DefaultSettingsViewController :
      UIViewController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>

PFLoginViewControllerDelegate 프로토콜은 델리게이트가 선택적으로 구현가능한 4개의 옵션 메소드를 가진다. 이 튜토리얼에서는 4개 모두 살펴 볼 것이다. 그러나 여러분의 구현에서는 필요에 따라 변경할 수 있다.

첫번째로, logInViewController: shouldBeginLogInWithUsername: password:메소드가 있다. 이 메소드는 로컬 유효성 검증에 따라서 로그인 과정을 중단 할 수 있다. 예제 앱에서는, 진행 전에 아이디와 비밀번호 입력란을 모두 완료하였는지 확인하기 위해 이 메소드를 사용 한다. 만약에 하나의 필드라도 비어 있으면 UIAlertView 를 화면에 보여준다. 그리고 로그인 프로세스는 NO를 리턴해서 중단한다. 만약 로그인이 중단 된 경우, Parse API 요청을 하지 않는다.

// 로그인 리퀘스트를 서버에 보낼지를 결정하기 위해 델리게이트에게 보낸다.
- (BOOL)logInViewController:(PFLogInViewController *)logInController shouldBeginLogInWithUsername:(NSString *)username password:(NSString *)password {
    // 두 개의 필드가 비었느지 확인한다.
    if (username && password && username.length != 0 && password.length != 0) {
        return YES; // 로그인 프로세스를 시작한다.
    }
     
    [[[UIAlertView alloc] initWithTitle:@"Missing Information"
                          message:@"Make sure you fill out all of the information!"
                          delegate:nil
                          cancelButtonTitle:@"ok"
                          otherButtonTitles:nil] show];
    return NO; // 로그인 프로세스를 중단한다.
}

두 번째 프로토콜 메소드는 사용자가 성공적으로 로그인 한 경우를 델리게이트에게 알려준다. 이번 예제 앱에서는 이전에 보여준 PFLogInViewController 를 단순하게 닫는다. 여러분의 앱에서는 프로필 사진 다운로드와 같은 로직을 수행하기 위해 이 메소드를 사용할 수 있다.

// PFUser가 로그인 되었을 때 델리게이트에게 보낸다.
- (void)logInViewController:(PFLogInViewController *)logInController didLogInUser:(PFUser *)user {
    [self dismissViewControllerAnimated:YES completion:NULL];
}

PFLogInViewControllerDelegate 프로토콜의 마지막 두 개의 메소드는 로그인 접속을 실패와 좌측 상단에 '닫기' 버튼을 터치 했을 경우를 다룬다. 아래 구현된 코드에서 보이는 것 처럼, 예제 앱의 루트 뷰 컨트롤러에 로그를 보여준다. 로그인이 실패 하였을 때 얼러트 뷰를 보여줄 수도 있다. 하지만 PFLoginViewController 에서 이미 기본적으로 보여준다.

// 로그인 시도가 실패 했을 때 델리게이트에 보낸다.
- (void)logInViewController:(PFLogInViewController *)logInController didFailToLogInWithError:(NSError *)error {
    NSLog(@"Failed to log in...");
}
 
// 로그인 화면이 닫혔을 경우 델리게이트에게 보낸다.
- (void)logInViewControllerDidCancelLogIn:(PFLogInViewController *)logInController {
    [self.navigationController popViewControllerAnimated:YES];
}

자유롭게 알맞게 사용하자.

1.3. PFSignUpViewControllerDelegate

PFSignUpViewControllerDelegate 프로토콜은 비슷한 설계를 따른다. 같은 페턴을 따르는 4개의 메소드를 가진다. 첫 번째로 가입 프로세스에 대한 중단으로 사용 할 수 있는 signUpViewController: shouldBeginSignUp: 메소드를 가진다. 로그인 델리게이트와 주요 차이점은 필드 정보가 키가 필드의 이름(username, password, 등) 경우 NSDictionary 로 제공된다는 점이다. 예제 앱에서는 모든 필드가 완료 되었는지 확인하기 위해 사용한다.

// 가입 리퀘스트가 서버에 제출 할지 여부를 결정하기 위해서 델리게이트에게 보낸다.
- (BOOL)signUpViewController:(PFSignUpViewController *)signUpController shouldBeginSignUp:(NSDictionary *)info {
    BOOL informationComplete = YES;
     
    // 제출된 데이터 모두를 루프를 한다.
    for (id key in info) {
        NSString *field = [info objectForKey:key];
        if (!field || field.length == 0) { // check completion
            informationComplete = NO;
            break;
        }
    }
     
    // 필드 값이 완성되지 않은 경우 경고 창을 보여준다.
    if (!informationComplete) {
        [[[UIAlertView alloc] initWithTitle:@"Missing Information"
                              message:@"Make sure you fill out all of the information!"
                              delegate:nil
                              cancelButtonTitle:@"ok"
                              otherButtonTitles:nil] show];
    }
     
    return informationComplete;
}

다른 세 개의 메소드들도 PFLogInViewControllerDelegate의 메소드에 1대 1로 맵핑된다. 이런것을 여러분의 앱에 맞게 사용할 수 있다.

// PFUser가 가입했으면 델리게이트에 보낸다.
- (void)signUpViewController:(PFSignUpViewController *)signUpController didSignUpUser:(PFUser *)user {
    [self dismissModalViewControllerAnimated:YES]; // Dismiss the PFSignUpViewController
}
 
// 가입이 실패 할 경우 델리게이트에 보낸다.
- (void)signUpViewController:(PFSignUpViewController *)signUpController didFailToSignUpWithError:(NSError *)error {
    NSLog(@"Failed to sign up...");
}
 
// 가입 화면이 닫혔을 경우 델리게이트에 보낸다.
- (void)signUpViewControllerDidCancelSignUp:(PFSignUpViewController *)signUpController {
    NSLog(@"User dismissed the signUpViewController");
}

2. 간단한 사용자 정의 및 소셜 연동

PFLoginViewController customized with social login options

이번 장에서는 예제 앱에서 프로퍼티를 통해서 로그인 뷰 컨트롤러를 사용자 정의를 할 수 있게 해주는 PropertyConfigViewController 를 다룰 것이다. 단 몇 줄의 코드로 트위터와 페이스북 계정을 사용하여 사용하여 우리의 앱에 사용자가 가입에 필요한 모든 로그인 작업 과정을 만들 수 있다.

시작하기 전에 소셜 네트워크에 필요한 계정을 만들기 위해서 페이스북  트위터 의 설정 가이드를 살펴보아라. 두 개의 소셜 네트워크를 사용하기 위해 앱에 앱에 프로퍼티 설정 방법을 보려면 이 장에서 설명된 과정을 이 튜토리얼의 AppDelegate 에서 비교 할 수 있다.

트위터와 페이스북의 설정 과정이 어렵지만, Parse와 연동과정은 죽도록 쉽다는 것을 보장한다.  1.1장처럼 컨트롤러의 viewDidAppear메소드에서  PFLoginViewController를 보여준다. 그러나 이번에는 소셜 네트워크 로그인 지원을 하기 위해 fields 프로퍼티를 설정한다. 사용자이름 로그인을 사용하지 않기 때문에, 가입 뷰 컨트롤러를 필요하지 않는 것을 확인 할 수 있다. 또한 facebookPermissions 프로퍼티를 사용자가 부여 할 권한 목록에 설정한다. 이러한 전체 허가 목록은 Facebook developer website에서 찾을 수 있다.

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
     
    if (![PFUser currentUser]) {       
        // 로그인 뷰 컨트롤러 사용자 정의하기.
        PFLogInViewController *logInViewController = [[PFLogInViewController alloc] init];
        [logInViewController setDelegate:self];
        [logInViewController setFacebookPermissions:[NSArray arrayWithObjects:@"friends_about_me", nil]];
        [logInViewController setFields: PFLogInFieldsTwitter | PFLogInFieldsFacebook | PFLogInFieldsDismissButton];
                 
        // 로그인 뷰 컨트롤러 보여주기.
        [self presentViewController:logInViewController animated:YES completion:NULL];
    }
}

정말 간단하다! 1.1장에서 본 같은 델리게이트 메소드를 성공, 실패, 창 닫기를 다룰 때 사용 할 수 있다. logInViewController: shouldBeginLogInWithUsername: password: 델리게이트 메소드는 트위터 또는 페이스북 로그인이 사용되었을 때는 호출 되지 않는다. 

다음 장에 보겠지만, 소셜 네트워크 로그인은 사용자이름과 패스워드 옵션에 상호 베타적이지 않다. 두 개 모두 공존 할 수 있고 사용자에게 여러가지 방법을 제공한다.

3. 완벽한 사용자 정의를 위해 서브클래싱하기

로그인과 가입 뷰 컨트롤러에 자신의 룩 앤 필을 주기 위해서, 서브 클래스를 할 수 있고 logInView과 signUpView 프로퍼티를 수정 할 수 있다. 이 튜토리얼의 마지막 장에서 예제 앱의 MyLogInViewController, MySignUpViewController  그리고 SubclassConfigViewController를 살펴보면서 작업의 방법을 볼 수 있다.

Custom PFLogInViewController subclass Custom PFSignUpViewController subclass

서브클래스의 viewDidLoad 그리고 viewDidLayoutSubviews 두 개 메소드를 오버라이딩 하면 사용자 정의를 할 수 있다. 대부분의 뷰 컨트롤러 처럼 추가와 수정하기 위해 전자를 사용한다. 후자에서 수행하는 유일한 작업은 뷰 엘리먼트의 프레임을 설정 하는 것이다.  Changing the frame in the viewDidLoad 메소드에서 프레임을 변경하는 것은 원하는 효과가 적용되지 않는다. 

3.1. PFLogInViewController 서브클래싱하기

사용자 정의한 로그인 뷰 서브클래스인 MyLogInViewController의 viewDidLoad 메소드에서 시작한다. 뷰 컨트롤러의 logInView 프로퍼티 접근으로 대부분 변경할 수 있는 것을 확인 할 수 있다. 이 뷰는 PFLogInView 종류이고 PFLogInViewController 화면에 표시되는 모든 엘리먼트를 포함한다. 

아래 구현을 살펴보고 나중에 무엇을 할지 논의 하자.

- (void)viewDidLoad
{
    [super viewDidLoad];
 
    [self.logInView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:@"main_background.png"]]];
    [self.logInView setLogo:[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo.png"]]];
 
    // 버튼 모양 설정
    [self.logInView.dismissButton setImage:[UIImage imageNamed:@"exit.png"] forState:UIControlStateNormal];
    [self.logInView.dismissButton setImage:[UIImage imageNamed:@"exit_down.png"] forState:UIControlStateHighlighted];
     
    [self.logInView.facebookButton setImage:nil forState:UIControlStateNormal];
    [self.logInView.facebookButton setImage:nil forState:UIControlStateHighlighted];
    [self.logInView.facebookButton setBackgroundImage:[UIImage imageNamed:@"facebook_down.png"] forState:UIControlStateHighlighted];
    [self.logInView.facebookButton setBackgroundImage:[UIImage imageNamed:@"facebook.png"] forState:UIControlStateNormal];
    [self.logInView.facebookButton setTitle:@"" forState:UIControlStateNormal];
    [self.logInView.facebookButton setTitle:@"" forState:UIControlStateHighlighted];
 
    [self.logInView.twitterButton setImage:nil forState:UIControlStateNormal];
    [self.logInView.twitterButton setImage:nil forState:UIControlStateHighlighted];
    [self.logInView.twitterButton setBackgroundImage:[UIImage imageNamed:@"twitter.png"] forState:UIControlStateNormal];
    [self.logInView.twitterButton setBackgroundImage:[UIImage imageNamed:@"twitter_down.png"] forState:UIControlStateHighlighted];
    [self.logInView.twitterButton setTitle:@"" forState:UIControlStateNormal];
    [self.logInView.twitterButton setTitle:@"" forState:UIControlStateHighlighted];
     
    [self.logInView.signUpButton setBackgroundImage:[UIImage imageNamed:@"signup.png"] forState:UIControlStateNormal];
    [self.logInView.signUpButton setBackgroundImage:[UIImage imageNamed:@"signup_down.png"] forState:UIControlStateHighlighted];
    [self.logInView.signUpButton setTitle:@"" forState:UIControlStateNormal];
    [self.logInView.signUpButton setTitle:@"" forState:UIControlStateHighlighted];
     
    // 로그인 필드 백그라운드 추가
    fieldsBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]];
    [self.logInView insertSubview:fieldsBackground atIndex:1];
     
    // 텍스트 그림자 삭제
    CALayer *layer = self.logInView.usernameField.layer;
    layer.shadowOpacity = 0.0;
    layer = self.logInView.passwordField.layer;
    layer.shadowOpacity = 0.0;
     
    // 필드의 텍스트 값 설정
    [self.logInView.usernameField setTextColor:[UIColor colorWithRed:135.0f/255.0f green:118.0f/255.0f blue:92.0f/255.0f alpha:1.0]];
    [self.logInView.passwordField setTextColor:[UIColor colorWithRed:135.0f/255.0f green:118.0f/255.0f blue:92.0f/255.0f alpha:1.0]];
 
}

배경화면을 이미지와 로고 필드에 "Parse"의 로고 대신 우리 앱의 로고로 변경한다. 배경화면 변경은 사용자이름과 패스워드 텍스트 필드 뒤의 테이블처럼 생긴 스타일을 지운다. 나중에 추가해야 한다.

다음으로 모든 버튼을 사용자 정의한 이미지로 변경한다. 예민한 사람은 몇 가지 케이스에 setImage 와 setBackgroundImage 를 사용한 것을 눈치 챘을 것이다. 버튼의 image 프로퍼티는 일반적으로 텍스트를 가진 아이콘을 화면에 보여줄 때 사용한다. 반면에 backgroundImage 는 배경화면으로 사용된다. Facebook과 Twitter 버튼의 케이스에서는 아이콘 이미지를 사용하지 않는다. 그래서 image 프로퍼티를 nil로 한다.

그리고 이미지뷰를 테이블 처럼 보이는 텍스트 필드 배경화면을 위해서 추가한다. 또한 텍스트 필드의 텍스트 색상과 그림자를 layer와 textColor프로퍼티를 변경해서 변경한다. 반약 뷰의 layer를 변경하기 위해서는 .m에 다음의 라인을 추가하여 QuartzCore를 임포트해야 한다.

#import <QuartzCore/QuartzCore.h>

우리의 로고와 버튼 이미지는 기본적인 것과 같은 크기가 아니기 때문에, 로고와 버튼 뷰의 프레임을 변경해야 한다. 이전에 말했던 것 처럼 viewDidLayoutSubviews 메소드에서 수정하면 된다.

- (void)viewDidLayoutSubviews {
    // 프레임을 위한 엘리먼트 설정.
    [self.logInView.dismissButton setFrame:CGRectMake(10, 10, 87.5, 45.5)];
    [self.logInView.logo setFrame:CGRectMake(66.5, 70, 187, 58.5)];
    [self.logInView.facebookButton setFrame:CGRectMake(35, 287, 120, 40)];
    [self.logInView.twitterButton setFrame:CGRectMake(35+130, 287, 120, 40)];
    [self.logInView.signUpButton setFrame:CGRectMake(35, 385, 250, 40)];
    [self.fieldsBackground setFrame:CGRectMake(35, 145, 250, 100)];
}

이것은 전부다! 완벽하게 사용자 정의가 된 PFLogInViewController를 만들었다. 물론, 만약에 가입 뷰 컨트롤러를 사용하기 원한다면 새로운 스타울로 사용자 정의를 해야 한다.

3.2. PFSignUpViewController 서브클래싱하기

1.2장 과 1.3장에서 본 델리게이트 처럼 로그인과 가입 뷰 컨트롤러의 뷰 사용자 정의에서는 많은 유사점이 있다. 수정을 추가하기 위해 동일한 두 개의 메소드를 사용한다. 그리고 signUpView 프로퍼티를 통하여 뷰 엘리먼트를 접근한다.

3.1장에서 구현 했던거와 매우 비슷하기 때문에 두 개의 메소드의 전체 코드를 살펴 보지 않을 것이다. 그러나 원한다면 full source code를 확인 할 수 있다.

viewDidLoad 메소드에서 살펴보기에 가치가 있는 수정사항이 있다. 만약에 가입 폼에서 추가적인 텍스트 필드를 추가해야 한다고 하면 "Additional"이라고 보여주고 싶지 않을 것이다. 매우 간단하게 이 텍스트를 사용자 정의 할 수 있다.

- (void)viewDidLoad {
    ...
    // 플레이스 홀더 텍스트를 "Additional"에서 "Phone number"로 변경하기
    [self.signUpView.additionalField setPlaceholder:@"Phone number"];
}

1.3장에서 본 것 처럼 델리게이션 메소드를 사용하여 입력된 텍스트가 전화번호 인지확인하는 추가적인 검증을 수행 할 수 있다.

viewDidLayoutSubviews의 구현에서 몇 가지 프레임을 변경 할 수 있다. 버튼과 로고 이외에도,  로고를 가득 채우기 위해서 전체 폼을 아래로 이동 시키고 싶다. 이것을 위해서, 각각의 텍스트 필드의 프레임 엘리멘트를 간단하게 변경하여 아래로 이동시킨다. 텍스트 필드를 기본 값 보다 작게 만드는 목적도 있다.

- (